std :: vector типа, выведенного из инициализаторов до C ++ 17 ... какой-нибудь обходной путь для C ++ 11? - PullRequest
4 голосов
/ 16 апреля 2019

Я узнал, что из C ++ 17 с помощью инструкций по выводу могут быть выведены аргументы шаблона std :: vector, например. из инициализации:

std::vector vec = { function_that_calculate_and_return_a_specifically_templated_type() }

Однако я не могу позволить себе роскошь C ++ 17 в машине, где я хочу сейчас скомпилировать и запустить код.

Есть ли возможный обходной путь для C ++ 11? Если существует больше решений, лучшим будет то, которое сохранит читабельность кода.

На данный момент единственная идея, которая у меня есть, - отслеживать различные случаи в коде (к счастью, их не должно быть слишком много) и делать некоторые явные typedef / using.

Любое предложение приветствуется

Ответы [ 2 ]

5 голосов
/ 16 апреля 2019

Обычным способом использования вывода типа для шаблона класса, когда CTAD недоступен, является предоставление шаблона функции make_*, например. для вашего случая (конечный тип возврата необходим для C ++ 11):

#include <vector>
#include <type_traits>
#include <tuple>

template <class ...Args>
auto make_vec(Args&&... args) ->
    std::vector<typename std::decay<typename std::tuple_element<0, std::tuple<Args...>>::type>::type>
{
   using First = typename std::decay<typename std::tuple_element<0, std::tuple<Args...>>::type>::type;

   return std::vector<First>{std::forward<Args>(args)...};
}

Вы можете вызвать вышеупомянутое с

const auto v = make_vec(1, 2, 3);

, который по крайней мере приближается к CTAD в том смысле, что вам не нужно явно указывать экземпляр вектора.

1 голос
/ 17 апреля 2019

Хотя ответ lubgr является правильным, следующий шаблон проще и, кажется, тоже работает:

#include <vector>
#include <string>

template <typename T>
std::vector<T> make_vec(const std::initializer_list<T> &list)
{
    return std::vector<T>(list);
}

int main()
{
    auto v = make_vec({1,2,3});
    auto v2 = make_vec({std::string("s")});
    std::string s("t");
    auto v3 = make_vec({s});
    return v.size() + v2.size() + v3.size();
}

Одним из преимуществ непосредственного использования шаблона initializer_list являются более четкие сообщения об ошибках, если вы передадитесмешанные типы, как в make_vec({1,2,"x"});, потому что создание неверного списка инициализатора теперь происходит в не шаблонном коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...