【问题标题】:class template fails to compile when named lambda is used as template class argument or constructor argument将命名 lambda 用作模板类参数或构造函数参数时,类模板无法编译
【发布时间】:2019-10-18 15:10:57
【问题描述】:

我目前正在尝试类模板编程,并且在将命名的 lambda 作为其参数传递时遇到了我无法理解的这种奇怪行为。有人可以解释为什么下面的 (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);
                ^

请原谅我的格式,并编译错误消息 sn-p,因为它与确切的行不匹配。我正在使用 g++ 7.4.0,并使用 c++17 功能进行编译。

【问题讨论】:

  • clang 告诉 cannot use parentheses when declaring variable with deduced class template specialization type 关于 (1)。 UPD 像宋元瑶所说的那样添加括号有帮助,lol

标签: c++ templates lambda class-template generic-lambda


【解决方案1】:

在 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】:

    正如你所说,这是一个最令人头疼的解析问题; Test(isEven); 正在尝试重新定义一个名为 isEven 的变量,对于 Test&lt;decltype(isEven)&gt;(isEven); 也是如此。

    正如您所展示的,您可以使用{} 而不是(),这是自C++11 以来的最佳解决方案;或者您可以添加额外的括号(使其成为函数式强制转换)。

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

    LIVE

    【讨论】:

      猜你喜欢
      • 2017-06-26
      • 1970-01-01
      • 2021-11-02
      • 1970-01-01
      • 2018-05-18
      • 2011-05-27
      • 1970-01-01
      • 2015-08-04
      • 1970-01-01
      相关资源
      最近更新 更多