C++ std::enable_if的不同编译器行为(取决于外部类模板参数)

C++ std::enable_if的不同编译器行为(取决于外部类模板参数),c++,c++11,templates,gcc,enable-if,C++,C++11,Templates,Gcc,Enable If,我有一个嵌套的(internal)类,我想根据封闭类(Outer)有多少模板参数(Args)为其启用构造函数 我想出了下面的代码,结果发现它在某些编译器上编译得很好,而在某些编译器上编译得不好 #包括 #包括 样板 结构外部{ 结构内部{ 内部(常量外部*外部,参数…VAL) :外部(外部) ,值(VAL…) {} //仅当参数为非空时,才应启用此ctor 模板> 内部(常数外部*外部) :外部(外部) {} 常量外部*外部; std::tuple 有趣的是结果: GCC 8.2-std=c+

我有一个嵌套的(
internal
)类,我想根据封闭类(
Outer
)有多少模板参数(
Args
)为其启用构造函数

我想出了下面的代码,结果发现它在某些编译器上编译得很好,而在某些编译器上编译得不好

#包括
#包括
样板
结构外部{
结构内部{
内部(常量外部*外部,参数…VAL)
:外部(外部)
,值(VAL…)
{}
//仅当参数为非空时,才应启用此ctor
模板>
内部(常数外部*外部)
:外部(外部)
{}
常量外部*外部;
std::tuple

有趣的是结果:

  • GCC 8.2-std=c++17
    -编译失败
  • GCC trunk-std=c++17
    -正常
  • MSVC 19.14/std:c++17/permissive-
    -OK
  • MSVC 19.16/std:c++17/permissive-
    -OK
  • clang7-std=c++17
    -编译失败
  • clangtrunk-std=c++17
    -编译失败

因此,问题是:

  • 外部
    类的
    参数…
    是否在
    内部
    类的直接上下文中
  • 上面的例子格式正确吗
  • 哪个编译器是对的
  • 为什么GCC开始在trunk上表现出不同的行为

如果依赖于构造函数模板参数,则需要使
std::enable\u

template <std::size_t N = sizeof...(Args), std::enable_if_t<(N > 0), bool> = true>
Inner(const Outer* out)
: outer(out)
{}
template=true>
内部(常数外部*外部)
:外部(外部)
{}
SFINAE仅适用于SFINAE依赖于函数模板参数的函数。这里不是。因此,硬错误是正确的

这可能是一种不需要诊断的情况,而您的程序仍然是病态的(因此编译器可以自由地做任何事情)。解决这个问题很棘手,因为有一个简单的解决方法,您不妨这样做

template <std::size_t N = sizeof...(Args), typename = std::enable_if_t<(N > 0)>>

Args…
为空时,我看不出这一点。

非常感谢,它在所有使用
template>
的编译器上都有效。我还感兴趣的是MSVC是否正确,或者说GCC在主干上是否有一个回归。@sthlm58-GCC主干仍在开发中。
std::enable\u if
在运行时有效为模板构造函数而不是类指定类型;MSVC是错误的。
template <typename = std::enable_if_t<false>>
     Inner(const Outer* out)
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>
    Inner(const Outer* out, Args... vals) 
        : outer(out)
        , values(vals...)
     {}