C ++ приводит std :: initializer_list к контейнеру в шаблонной функции - PullRequest
0 голосов
/ 21 мая 2018

Я не могу передать список инициализатора в шаблонную функцию, чтобы затем вызвать функцию без шаблонов, которая привела бы список инициализатора к контейнеру.Однако при пропуске промежуточной шаблонной функции она компилируется.

#include <iostream>
#include <vector>

struct MyLoader {
    static auto load(const std::vector<int> &v) {
        return v;
    }
};

template<typename Loader, typename... Args>
auto makeVector(Args&&... args) {
    return Loader::load(std::forward<Args>(args)...);
}

int main() {
    auto v = makeVector<MyLoader>({ 8, 8, 8 });

    for (auto x : v) {
        std::cout << x << "\n";
    }
}

Визуализирует ошибку:

main.cpp: In instantiation of 'auto makeVector(Args&& ...) [with Loader = MyLoader; Args = {}]':
main.cpp:18:46:   required from here
main.cpp:13:24: error: no matching function for call to 'MyLoader::load()'
     return Loader::load(std::forward<Args>(args)...);
            ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:6:17: note: candidate: 'static auto MyLoader::load(const std::vector<int>&)'
     static auto load(const std::vector<int> &v) {
                 ^~~~
main.cpp:6:17: note:   candidate expects 1 argument, 0 provided
main.cpp: In function 'int main()':
main.cpp:18:46: error: too many arguments to function 'auto makeVector(Args&& ...) [with Loader = MyLoader; Args = {}]'
     auto v = makeVector<MyLoader>({ 8, 8, 8 });
                                              ^
main.cpp:12:6: note: declared here
 auto makeVector(Args&&... args) {
      ^~~~~~~~~~
main.cpp:18:10: error: 'void v' has incomplete type
     auto v = makeVector<MyLoader>({ 8, 8, 8 });
          ^
main.cpp:20:19: error: unable to deduce 'auto&&' from 'v'
     for (auto x : v) {

Однако следующее прекрасно компилируется:

#include <iostream>
#include <vector>

struct MyLoader {
    static auto load(const std::vector<int> &v) {
        return v;
    }
};

int main() {
    auto v = MyLoader::load({ 8, 8, 8 });

    for (auto x : v) {
        std::cout << x << "\n";
    }
}

Почему список инициализаторов не приведен к аргументу std::vector MyLoader::load() в первом примере?

1 Ответ

0 голосов
/ 21 мая 2018

Проблема в том, что {8, 8, 8} не выводится как тип.

Если вы передаете его методу, который получает const std::vector<int>, все идет хорошо, потому что компилятор знает, что используется {8, 8, 8}инициализировать std::vector<int>.

Но если вы передадите его функции, которая получает список переменных (Args&&... args) из неизвестных типов аргументов, это не работает, потому что компиляторне знает, что тип ведьмы {8, 8, 8}.

Предложение: передайте значения вариативным способом

auto v = makeVector<MyLoader>(8, 8, 8);

, чтобы компилятор мог определить Args... как int, int, int и передатьload() добавление графиков

// ------------------V-----------------------------V   
return Loader::load( { std::forward<Args>(args)... } );

Если вы действительно (действительно!) хотите передать значения в makeVector() в качестве списка инициализации, вы можете перехватить их как массив

template <typename Ldr, std::size_t Dim, typename Arg>
auto makeVector (Arg(&&arg)[Dim])

Таким образом, компилятор может определить тип (Arg, как int) и размер (Dim, 3 в случае {8, 8, 8}.

. Но для распаковки массива вам понадобитсяиндексы, так что помощник функции.

что-то вроде

template <typename Ldr, std::size_t ... Is, std::size_t Dim, typename Arg>
auto makeVectorH (std::index_sequence<Is...> const &, Arg(&&arg)[Dim])
 { return Ldr::load({std::forward<Arg>(arg[Is])...}); }

template <typename Ldr, std::size_t Dim, typename Arg>
auto makeVector (Arg(&&arg)[Dim])
 { return makeVectorH<Ldr>(std::make_index_sequence<Dim>{},
                           std::forward<Arg[Dim]>(arg)); }

Ниже приведен пример полной компиляции C ++ 14 для массива case (но я предлагаю более простое использование переменных аргументов)

#include <vector>
#include <utility>
#include <iostream>

struct MyLoader
 { static auto load(const std::vector<int> &v) { return v; } };

template <typename Ldr, std::size_t ... Is, std::size_t Dim, typename Arg>
auto makeVectorH (std::index_sequence<Is...> const &, Arg(&&arg)[Dim])
 { return Ldr::load({std::forward<Arg>(arg[Is])...}); }

template <typename Ldr, std::size_t Dim, typename Arg>
auto makeVector (Arg(&&arg)[Dim])
 { return makeVectorH<Ldr>(std::make_index_sequence<Dim>{},
                           std::forward<Arg[Dim]>(arg)); }

int main ()
 {
   auto v = makeVector<MyLoader>({8, 8, 8});

   for (auto x : v)
        std::cout << x << "\n";
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...