C++11 模板演绎上下文中受保护的成员:编译错误、替换失败或成功?

C++11 模板演绎上下文中受保护的成员:编译错误、替换失败或成功?,c++11,g++,clang,access-modifiers,sfinae,C++11,G++,Clang,Access Modifiers,Sfinae,当g++5.2.1在模板演绎上下文中遇到私有方法的地址时,它无法编译,而clang 3.5仅放弃专门化。 当clang 3.5有时无法访问时,g++5.2.1可以访问类模板参数列表中受保护的家长/朋友成员。 在哪些情况下哪些是错误的 更准确地说: 当试图访问模板上下文中不可访问的受保护/私有成员时,编译器是否会导致硬错误?在我的第一个例子中,我做错了什么吗 如果不是,编译器在尝试访问(在模板演绎上下文中)由以下对象拥有的受保护成员时是否应放弃专门化: 这个特殊专业化的基类 将此特定实例化声明

当g++5.2.1在模板演绎上下文中遇到私有方法的地址时,它无法编译,而clang 3.5仅放弃专门化。
当clang 3.5有时无法访问时,g++5.2.1可以访问类模板参数列表中受保护的家长/朋友成员。
在哪些情况下哪些是错误的

更准确地说:

  • 当试图访问模板上下文中不可访问的受保护/私有成员时,编译器是否会导致硬错误?在我的第一个例子中,我做错了什么吗

  • 如果不是,编译器在尝试访问(在模板演绎上下文中)由以下对象拥有的受保护成员时是否应放弃专门化:

    • 这个特殊专业化的基类

    • 将此特定实例化声明为友元的类

    • 将此模板的任何实例化声明为友元的友元类

第一个问题似乎已经得到了回答(答案似乎是“不,代码不是格式错误的,编译器应该放弃这种专门化”)。但是,由于这是第二个问题的先决条件(而且g++5.2.1似乎不同意),我想绝对确定错误的是g++5.2.1,而不是我


带示例的较长版本 我想让traits能够检测是否实现了某些函数/方法,即使它们是某个类的受保护成员(如果你觉得这很奇怪,我会在问题的最后解释我为什么要这么做,这样你就可以告诉我我完全错了,我应该学习如何设计我的类,也许可以建议我一种更简洁的方法来设计)。
我的问题是,我的每一次尝试在clang或g++上都失败了(奇怪的是,并不是同时在这两个平台上):有时它编译了,但没有提供预期的结果,有时它根本没有编译。
尽管这看起来不实用,但我至少想知道编译器什么时候出了问题,什么时候我在写格式错误的代码。因此这个问题

我使用C++11方言,我的clang版本实际上是XCode 5提供的编译器,即Apple LLVM版本6.0(clang-600.0.57)(基于LLVM 3.5svn)

为了更好地说明我的问题所在,下面是一个示例,其中clang编译,但g++5.2.1不编译:

#include <iostream>
#include <type_traits>
#include <utility>

struct PrivateFoo {
private:
  void foo() {}
};

/* utilities */

// reimplement C++17's std::void_t
template<class...>
struct void_type {
  typedef void type;
};

template<class... T>
using void_t = typename void_type<T...>::type;

// dummy class used to check whether a pointer to (possibly member) function
// exists with the good signature
template<class T, T>
struct check_signature {};

/* traits */

template<class C, class = void>
struct has_foo : std::false_type {};

template<class C>
struct has_foo<C, void_t<check_signature<void(C::*)(), &C::foo>>> :
std::true_type {};

int main() {
  std::cout << std::boolalpha;
  std::cout << "PrivateFoo has foo: " << has_foo<PrivateFoo>::value << '\n';
  return 0;
}
3.5版本的输出:

PrivateFoo has foo: false ProtectedFoo has foo: false ProtectedFoo has foo: true 3.5版本的输出:

PrivateFoo has foo: false ProtectedFoo has foo: false ProtectedFoo has foo: true ProtectedFoo有foo:true 使用g++5.2.1输出:

ProtectedFoo has foo: true ProtectedFoo has foo: true ProtectedFoo有foo:true 这里还有一个更完整的示例,总结了这一切:

#include <iostream>
#include <type_traits>
#include <utility>

/* test classes */

struct PublicFoo {
  void foo() {}
};

struct ProtectedFoo {
protected:
  void foo() {}
};

struct PrivateFoo {
private:
  void foo() {}
};

struct NoFoo {};

/* utilities */

// reimplement C++17's std::void_t
template<class...>
struct void_type {
  typedef void type;
};

template<class... T>
using void_t = typename void_type<T...>::type;

// dummy class used to check whether a pointer to (possibly member) function
// exists with the good signature
template<class T, T>
struct check_signature {};

/* traits */

namespace detail {
  template<class C, class D, class = void>
  struct has_foo_helper : std::false_type {};

  template<class C, class D>
  struct has_foo_helper<C, D, void_t<check_signature<void(C::*)(), &D::foo>>> :
  std::true_type {};

  template<class C, class = void>
  struct may_call_foo_helper : std::false_type {};

  template<class C>
  struct may_call_foo_helper<C, void_t<decltype(std::declval<C>().foo())>> :
  std::true_type {};
}

template<class C>
struct has_foo : detail::has_foo_helper<C, C> {};

template<class C>
struct may_call_foo : detail::may_call_foo_helper<C> {};

template<class C>
struct has_protected_foo : protected C {
  template<class, class, class>
  friend class detail::has_foo_helper;

  static constexpr bool value =
  detail::has_foo_helper<C, has_protected_foo<C>>::value;
};

template<class C>
struct may_call_protected_foo : protected C {
  template<class, class>
  friend class detail::may_call_foo_helper;

  static constexpr bool value =
  detail::may_call_foo_helper<may_call_protected_foo<C>>::value;
};

/* test */

template<class T>
void print_info(const char* classname) {
  std::cout << classname << "...\n";
  // comment this if you want to compile with g++
  //*
  std::cout << "has a public method \"void foo()\": ";
  std::cout << has_foo<T>::value << '\n';
  std::cout << "has a public or protected method \"void foo()\": ";
  std::cout << has_protected_foo<T>::value << '\n';
  //*/
  std::cout << "has a public method \"foo\" callable without any arguments: ";
  std::cout << may_call_foo<T>::value << '\n';
  std::cout << "has a public or protected method \"foo\" callable without any "
               "arguments: ";
  std::cout << may_call_protected_foo<T>::value << '\n';
  std::cout << '\n';
}

int main() {
  std::cout << std::boolalpha;
  // both g++ 5.2.1 and clang 3.5 compile
  print_info<PublicFoo>("PublicFoo");
  // g++ 5.2.1 fails to compile has_foo, clang 3.5 compiles fine
  print_info<ProtectedFoo>("ProtectedFoo");
  // g++ 5.2.1 fails to compile, clang 3.5 compiles fine
  print_info<PrivateFoo>("PrivateFoo");
  // both g++ 5.2.1 and clang 3.5 compile
  print_info<NoFoo>("NoFoo");
  return 0;
}
#包括
#包括
#包括
/*测试班*/
结构PublicFoo{
void foo(){}
};
struct ProtectedFoo{
受保护的:
void foo(){}
};
私有结构{
私人:
void foo(){}
};
结构NoFoo{};
/*公用事业*/
//重新实现C++17的std::void\t
模板
结构void_类型{
typedef-void型;
};
模板
使用void\u t=typename void\u type::type;
//用于检查指向(可能是成员)函数的指针
//以良好的签名存在
模板
结构检查_签名{};
/*特征*/
名称空间详细信息{
模板
结构有\u foo\u helper:std::false\u type{};
模板
结构具有\u foo\u帮助程序:
std::true_type{};
模板
结构可以调用\u foo\u helper:std::false\u type{};
模板
结构可以调用\u foo\u助手:
std::true_type{};
}
模板
结构has_foo:detail::has_foo_helper{};
模板
结构may_调用\u foo:detail::may_调用\u foo\u helper{};
模板
结构已\u受保护\u foo:protected C{
模板
好友类详细信息::has_foo_helper;
静态constexpr布尔值=
细节::has_foo_helper::value;
};
模板
结构可以调用\u protected\u foo:protected C{
模板
好友类详细信息::may_call_foo_helper;
静态constexpr布尔值=
细节::may_call_foo_helper::value;
};
/*试验*/
模板
无效打印信息(常量字符*类名){

你的第一个例子肯定是,我也想知道这个问题的答案。