我有一个嵌套(Inner
)类,我想为其构建一个enable_if
的构造函数,具体取决于封闭类({{1} })。
我想出了下面的代码,只是发现它在某些编译器上可以正常编译,而在某些编译器上则可以。
Args
在Godbolt上显示:https://godbolt.org/z/lsivO9
有趣的部分是结果:
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);
}
-确定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
是否在Args...
类的直接上下文中? 答案 0 :(得分:3)
您需要使std::enable_if
依赖于构造函数模板参数
template <std::size_t N = sizeof...(Args), std::enable_if_t<(N > 0), bool> = true>
Inner(const Outer* out)
: outer(out)
{}
答案 1 :(得分:1)
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...
为空时,所以这里看不到重点。