我正在尝试通过比较 Visual Studio 的输出和 GCC 的输出来调试我在 Visual Studio 中遇到的问题,但我似乎无法获得在 Ideone 中编译的极其简化的代码版本:

#include <exception>
#include <iostream>

template <int x>
struct foo {};

template <>
struct foo<0> { using type = int; };

template <typename Foo>
struct bar
{
    bar(void) {}

    template <typename = typename Foo::type>
    bar(const bar &) {}
};

int main(void)
{
    bar<foo<1>> x;
}

当我尝试使用 Ideone 运行它时,上面给了我错误:
prog.cpp: In instantiation of ‘struct bar<foo<1> >’:
prog.cpp:21:17:   required from here
prog.cpp:16:5: error: no type named ‘type’ in ‘struct foo<1>’
     bar(const bar &) {}

根据我的理解,替换 Foo::type 失败应该不会导致编译错误。请注意,使复制构造函数 bar(const bar &) { typename Foo::type x; } 允许程序编译得很好。我正在尝试以与使用 std::enable_if 几乎完全相同的方式使用此模板,这在类中的任何地方使用时也会导致编译错误 - 不仅仅是在复制构造函数上。这是正确的行为吗?我相当肯定它不是,但我一直认为 Ideone 在后端使用 GCC ......

最佳答案

是的,这种行为是正确的。

SFINAE 适用于在函数模板重载解析 期间 推导模板参数时(允许编译器丢弃特化而不发出错误)。

在您的情况下,错误不是在重载解析期间发生,而是在模板实例化期间发生: bar 模板根本无法实例化,因为复制构造函数需要存在嵌套类型 Foo::type ,当模板参数为 foo<1> 时不存在.

对于你的最后一点,如果你声明:

template <typename Foo>
struct bar
{
    bar(void) {}

    bar(const bar &) { typename Foo::type x; }
};

只要您不调用复制构造函数,它就可以很好地编译。
使用复制构造函数将导致相同的编译错误:
bar<foo<1>> x2 = x; // Error

关于c++ - Ideone 中的 SFINAE 问题?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26111044/

10-13 08:23