C++11 模板演绎上下文中受保护的成员:编译错误、替换失败或成功?
当g++5.2.1在模板演绎上下文中遇到私有方法的地址时,它无法编译,而clang 3.5仅放弃专门化。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可以访问类模板参数列表中受保护的家长/朋友成员。 在哪些情况下哪些是错误的 更准确地说: 当试图访问模板上下文中不可访问的受保护/私有成员时,编译器是否会导致硬错误?在我的第一个例子中,我做错了什么吗 如果不是,编译器在尝试访问(在模板演绎上下文中)由以下对象拥有的受保护成员时是否应放弃专门化: 这个特殊专业化的基类 将此特定实例化声明
当clang 3.5有时无法访问时,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;
};
/*试验*/
模板
无效打印信息(常量字符*类名){
你的第一个例子肯定是,我也想知道这个问题的答案。