如果我的模板类型首先作为 lambda 参数出现,MSVC 会引发一个奇怪的错误

Posted

技术标签:

【中文标题】如果我的模板类型首先作为 lambda 参数出现,MSVC 会引发一个奇怪的错误【英文标题】:If my templated type occurs firstly as a lambda argument, MSVC raises a strange error 【发布时间】:2017-06-01 12:29:45 【问题描述】:

考虑这段代码:

#define SOLUTION 0

template <class T>
constexpr int one = 1;

template <class T>
struct A 
    static constexpr int o = one<A<T>>;

    void call() 
        static_assert(one<A<T>> == 1, "Failure");
    
;

int main() 
#if SOLUTION
    A<int> object;
#endif

    [](A<int> a) 
        a.call();
    ;

    return 0;

无论SOLUTION定义的值如何,它都会成功构建here on ideone。

现在,我知道这段代码没有什么实际意义,但那是因为我正在认真地尝试找到这种奇怪行为的最小工作示例。如果我使用最新的 Visual Studio 2017(平台工具集 v141,_MSC_VER = 1910)构建它,我会收到以下错误:

1>source.cpp(11): error C2131: expression did not evaluate to a constant
1>source.cpp(11): note: failure was caused by a read of an uninitialized symbol
1>source.cpp(11): note: see usage of 'one<A<int>>'
1>source.cpp(10): note: while compiling class template member function 'void A<int>::call(void)'
1>source.cpp(21): note: see reference to function template instantiation 'void A<int>::call(void)' being compiled
1>source.cpp(21): note: see reference to class template instantiation 'A<int>' being compiled

有趣的是,当我为 SOLUTION 宏设置 1 时,它会成功构建。唯一的区别是在编译器到达 lambda 定义之前,main 的作用域中定义了一个未使用的 A&lt;int&gt; object; 变量。

如果在 main 之前定义一个这样的函数也很好:

void f(A<int>& a) 
    a.call();

事实上它和变量定义一样很好地解决了这个问题。

是编译器的错误还是上面的代码块违反了标准?

【问题讨论】:

在 VS2017 更新 3 上编译,但不在 (RTM) 更新 2 上编译。 @Ajay Strange,我的 VS2017 版本似乎是最新的,于 5 月 30 日更新,因此实际上是 3 天前。也许它是否是社区版本很重要(我的是社区)?我也注意到这里的问题的开发人员:developercommunity.visualstudio.com/content/problem/63753/… 我也确认它不会发生在我自己的机器上。 我已经安装了更新 3 的预览版,它有很多 C++17 特性。 @Ajay 哇,不知道预览!我马上试试看。 【参考方案1】:

引用Ajay:

在 VS2017 更新 3 上编译,但不在 (RTM) 更新 2 上编译

我也在我的机器上确认了这种行为。这意味着相关的更正已经存在,并且很快就会引入生产版本本身,所以我认为这个错误不值得进一步关注。

【讨论】:

以上是关于如果我的模板类型首先作为 lambda 参数出现,MSVC 会引发一个奇怪的错误的主要内容,如果未能解决你的问题,请参考以下文章

C++20:非类型模板参数中的非捕获 lambda

Lambda 作为函数参数

将 lambda 参数完美转发给成员函数,其中成员函数是非类型模板形参

将 lambda 作为模板参数传递给函数指针函数模板化

如何使用 lambda 表达式作为模板参数?

C++Lambda表达式作为参数