шаблон класса не компилируется, когда именованная лямбда используется в качестве аргумента класса шаблона или аргумента конструктора - PullRequest
5 голосов
/ 03 июня 2019

В настоящее время я экспериментирую с программированием шаблонов классов и натолкнулся на странное поведение, которое я не могу понять, передавая именованную лямбду в качестве аргумента. Может ли кто-нибудь объяснить, почему (1) и (2) ниже не работает?

template<typename Predicate>
class Test{
public:
    Test(Predicate p) : _pred(p) {}
private:
    Predicate _pred;
};

int main(){
    auto isEven = [](const auto& x){ return x%2 == 0; };

    // Working cases
    Test([](const auto& x){ return x%2 == 0; });
    Test{isEven};
    auto testObject = Test(isEven);

    // Compilation Error cases
    Test(isEven); // (1) Why??? Most vexing parse? not assigned to a variable? I cant understand why this fails to compile.
    Test<decltype(isEven)>(isEven); // (2) Basically same as (1) but with a workaround. I'm using c++17 features, so I expect automatic class parameter type deduction via its arguments

    return 0;
};

Сообщение об ошибке компилятора: То же самое для (1) и (2)

cpp/test_zone/main.cpp: In function ‘int main()’:
cpp/test_zone/main.cpp:672:16: error: class template argument deduction failed:
     Test(isEven);
                ^
cpp/test_zone/main.cpp:672:16: error: no matching function for call to ‘Test()’
cpp/test_zone/main.cpp:623:5: note: candidate: template<class Predicate> Test(Predicate)-> Test<Predicate>
     Test(Predicate p): _p(p){
     ^~~~
cpp/test_zone/main.cpp:623:5: note:   template argument deduction/substitution failed:
cpp/test_zone/main.cpp:672:16: note:   candidate expects 1 argument, 0 provided
     Test(isEven);
                ^

Пожалуйста, простите мое форматирование и скомпилируйте фрагмент сообщения об ошибке, так как он не соответствует точным строкам. Я использую g ++ 7.4.0 и компилирую с возможностями c ++ 17.

Ответы [ 2 ]

4 голосов
/ 03 июня 2019

В C ++ вы можете объявить переменную как

int(i);

, что совпадает с

int i;

В вашем случае строки

Test(isEven);
Test<decltype(isEven)>(isEven);

скомпилированы так, как будто вы объявляете переменную isEven.Я удивлен, что сообщение об ошибке вашего компилятора настолько отличается от того, что я надеялся увидеть.

Вы можете воспроизвести проблему и с простым классом.

class Test{
   public:
      Test(int i) : _i(i) {}
   private:
      int _i;
};

int main(){

   int i = 10;

   Test(i);
   return 0;
};

Ошибка моего компилятора, g ++ 7.4.0:

$ g++ -std=c++17 -Wall    socc.cc   -o socc
socc.cc: In function ‘int main()’:
socc.cc:15:11: error: conflicting declaration ‘Test i’
     Test(i);
           ^
socc.cc:10:9: note: previous declaration as ‘int i’
     int i = 10;
2 голосов
/ 03 июня 2019

Как вы сказали, это самая неприятная проблема с разбором;Test(isEven); пытается переопределить переменную с именем isEven, и то же самое для Test<decltype(isEven)>(isEven);.

Как вы показали, вы можете использовать {} вместо (), это лучшее решение, посколькуC ++ 11;или вы можете добавить дополнительные скобки (чтобы сделать приведение в стиле функции).

(Test(isEven));
(Test<decltype(isEven)>(isEven)); 

LIVE

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