[英]Different behavior across compilers for std::enable_if (dependent on Outer class template parameters)
我有一个嵌套( Inner
)类,为此,我想enable_if
构造,这取决于模板多少个参数( Args
)封装类( Outer
)了。
我想出了下面的代码,只是发现它在某些编译器上可以正常编译,而在某些编译器上则可以。
#include <tuple>
#include <type_traits>
template <typename... Args>
struct Outer {
struct Inner {
Inner(const Outer* out, Args... vals)
: outer(out)
, values(vals...)
{}
// This ctor should be enabled only if Args are non-empty
template <typename = std::enable_if_t<(sizeof...(Args) > 0)>>
Inner(const Outer* out)
: outer(out)
{}
const Outer* outer;
std::tuple<Args...> values;
};
};
int main()
{
Outer<int, int> o1;
Outer<int, int>::Inner i1(&o1, 1, 2);
Outer<int, int>::Inner i11(&o1);
Outer<> o2;
Outer<>::Inner i2(&o2);
Outer<>::Inner i21(nullptr);
}
在Godbolt上显示: https ://godbolt.org/z/lsivO9
有趣的部分是结果:
GCC 8.2 -std=c++17
编译失败 GCC trunk -std=c++17
确定 MSVC 19.14 /std:c++17 /permissive-
确定 MSVC 19.16 /std:c++17 /permissive-
确定 clang 7 -std=c++17
编译失败 clang trunk -std=c++17
编译失败 因此,问题是:
Outer
类的Args...
是Inner
类的直接上下文吗? 您需要使std::enable_if
依赖于构造函数模板参数
template <std::size_t N = sizeof...(Args), std::enable_if_t<(N > 0), bool> = true>
Inner(const Outer* out)
: outer(out)
{}
template <typename = std::enable_if_t<(sizeof...(Args) > 0)>>
Inner(const Outer* out)
当Args
为空时,这是
template <typename = std::enable_if_t<false>>
Inner(const Outer* out)
仅当SFINAE依赖于函数的模板参数时,SFINAE才适用于函数。 这里不是。 因此,硬错误是适当的。
在这种情况下,可能不需要诊断,并且程序仍然格式错误(因此编译器可以随意执行任何操作)。 解决这个问题很棘手,并且由于有一个简单的解决方法,因此您最好也这样做。
template <std::size_t N = sizeof...(Args), typename = std::enable_if_t<(N > 0)>>
还是我的首选
template <std::size_t N = sizeof...(Args), std::enable_if_t<(N > 0), bool> = true>
过载时效果更好。
但是,在您的特定情况下,第一个ctor变为第二个:
Inner(const Outer* out, Args... vals)
: outer(out)
, values(vals...)
{}
当Args...
为空时,我在这里看不到要点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.