【问题标题】:SFINAE and visibility-checking in Clang vs. GCC vs. MSVC -- which is correct?Clang、GCC 和 MSVC 中的 SFINAE 和可见性检查——哪个是正确的?
【发布时间】:2014-08-13 10:12:33
【问题描述】:

我已经编写了我对 is_default_constructible 的 C++03 兼容实现的尝试:

template<class = void> struct is_default_constructible;
template<> struct is_default_constructible<>
{
protected:
    // Put base typedefs here to avoid pollution
    struct twoc { char a, b; };
    template<bool> struct test { typedef char type; };
    template<class T> static T declval();
};
template<> struct is_default_constructible<>::test<true> { typedef twoc type; };
template<class T> struct is_default_constructible : is_default_constructible<>
{
private:
    template<class U> static typename test<!!sizeof(::new U())>::type sfinae(U*);
    template<class U> static char sfinae(...);
public:
    static bool const value = sizeof(sfinae<T>(0)) > 1;
};

当我在 GCC (-std=c++03) 中测试它时,它返回 0,因为构造函数是不可见的:

class Test { Test(); };

int main()
{
    return is_default_constructible<Test>::value;
}

当我在 Visual C++ 中测试它时(不同的版本都有相同的行为),我得到了1

当我在 Clang(也是 -std=c++03)中测试它时,我得到:

error: calling a private constructor of class 'Test'
template<class U> static typename test<!!sizeof(::new U())>::type sfinae(U *);
                                                      ^
note: while substituting explicitly-specified template arguments into function template 'sfinae' 
static bool const value = sizeof(sfinae<T>(0)) > 1;
                                 ^
note: in instantiation of template class 'is_default_constructible<Test>' requested here
return is_default_constructible<Test>::value;
       ^
error: calling a private constructor of class 'Test'
template<class U> static typename test<!!sizeof(::new U())>::type sfinae(U *);
                                                      ^
note: while substituting deduced template arguments into function template 'sfinae' [with U = Test]
static bool const value = sizeof(sfinae<T>(0)) > 1;
                                 ^
note: in instantiation of template class 'is_default_constructible<Test>' requested here
return is_default_constructible<Test>::value;

哪个编译器是正确的,为什么?

【问题讨论】:

  • 顺便说一句,如果这是重复的,我不会感到惊讶,所以如果是,请关闭。不过搜索起来并不容易。
  • 当你说:with gcc, with clang, etc.时请务必指定版本。
  • @MarcGlisse:我不明白它为什么重要,但它是 Clang 3.6.0 和 GCC 4.8.1。
  • @Mehrdad:考虑到是否在 SFINAE 上下文中考虑可见性在 C++11 中发生了变化,这很重要。早于那个(或遵循旧规则,包括 g++4.4)的编译器将由于可访问性问题而失败,而使用 C++11 规则的编译器不会考虑它。
  • @David:但我想我已经说过我在 C++03 模式下执行此操作......这还不够吗?

标签: c++ template-meta-programming sfinae c++03 access-specifier


【解决方案1】:

代码不是有效的 C++03,尽管它是有效的 C++11。 g++ 4.8 编译器遵守 C++11 规则并忽略 SFINAE 上下文中不可访问的成员,而 clang 编译器遵守 C++03,其中找到并选择了成员(在这种情况下为构造函数),但访问检查使代码无效。 VS(无论您使用什么版本)不遵守 C++11 或 C++03 规则,它似乎完全忽略了sizeof 中的访问说明符。

【讨论】:

  • 要么你混淆了编译器,要么我不理解你的答案,因为显然 VC++ 不认为代码是无效的......
  • @Mehrdad:在 VS 中,您无法控制它是以 C++03 还是 C++11 模式构建的,它只有一种模式。在 C++03 中代码无效(硬错误),在 C++11 中,访问检查是作为替换过程的一部分完成的,SFINAE 应该启动并选择省略号重载。总结:clang++正确遵循C++03规则,g++遵循C++11规则(即使-std=c++03!),VS没有正确遵循C++03和C++11规则。
  • 是的,我明白,让我感到困惑的是,您说“其他编译器”遵守 C++03,这没有任何意义,但我看到您现在已修复它。
猜你喜欢
  • 2016-09-15
  • 2014-11-02
  • 2022-12-08
  • 1970-01-01
  • 2015-03-25
  • 2018-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多