Почему здесь есть разница между инициализацией скобок и скобок? - PullRequest
4 голосов
/ 14 января 2020

Я пытаюсь воссоздать простой пример из этой статьи о распространенном трюке "перегруженной лямбды", чтобы создать набор перегрузки, который можно использовать с std::visit или другими подобными средствами. Мой упрощенный пример:

#include <iostream>
#include <vector>

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; // (1)
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;  // (2)

int main() {

    overloaded os(
        [](int i) { std::cout << "int: " << i << std::endl; }, 
        [](const char *str) { std::cout << "str: " << str << std::endl; }
    );

    os(1);
    os("Hello world!");

    return 0;
}

Это не компилируется .

<source>: In function 'int main()':
<source>:12:5: error: no matching function for call to 'overloaded<main()::<lambda(int)>, main()::<lambda(const char*)> >::overloaded(main()::<lambda(int)>, main()::<lambda(const char*)>)'
   12 |     );
      |     ^
<source>:4:30: note: candidate: 'constexpr overloaded<main()::<lambda(int)>, main()::<lambda(const char*)> >::overloaded(const overloaded<main()::<lambda(int)>, main()::<lambda(const char*)> >&)'
    4 | template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; // (1)
      |                              ^~~~~~~~~~
<source>:4:30: note:   candidate expects 1 argument, 2 provided
<source>:4:30: note: candidate: 'constexpr overloaded<main()::<lambda(int)>, main()::<lambda(const char*)> >::overloaded(overloaded<main()::<lambda(int)>, main()::<lambda(const char*)> >&&)'
<source>:4:30: note:   candidate expects 1 argument, 2 provided

Если я изменю инициализацию overloaded os на использование инициализации фигурной скобки, , тогда она будет работать . Кто-нибудь может объяснить здесь разницу?

1 Ответ

4 голосов
/ 14 января 2020

Вот сокращенный пример без каких-либо шаблонов:

struct A { };
struct B { };

struct C : A, B { };

C x(A{}, B{}); // error
C y{A{}, B{}}; // ok

Проблема: C - это агрегат, поэтому вы можете использовать агрегатную инициализацию для инициализации его компонентов. Вот почему y работает. Но C является агрегатом, у него нет конструкторов, что пытается сделать инициализация x. Нет такого подходящего конструктора, следовательно, он не работает. Обратите внимание, что в C ++ 20 x также будет работать, потому что мы сможем выполнить агрегатную инициализацию с круглыми скобками.

Чтобы получить объявление x для компиляции, добавьте конструктор:

struct C : A, B {
    C(A a, B b) : A(a), B(b) { }
};

Или для исходной задачи:

template<class... Ts>
struct overloaded : Ts... {
    overloaded(Ts... ts) : Ts(std::move(ts))... { } // <==
    using Ts::operator()...;
};

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

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