这是我的unsuccessful attempt,用于检测C ++ 98/03中是否存在任何类/结构void set( T& , void (T::*Func)( const char* ) , const char* str )
的独立函数T
。
#include <iostream>
#include <typeinfo>
struct Foo;
struct Bar;
struct Fuu;
void set( Foo& , void (Foo::*Func)( const char* ) , const char* str )
{
}
void set( Bar& , void (Bar::*Func)( const char* ) , const char* str )
{
}
template <typename T>
class setter_is_implemented
{
public:
typedef void (*SetterFunction)( T& , void (T::*)( const char* ) , const char* );
typedef char one;
typedef long two;
template <typename C> static one test( C c, SetterFunction = c ) ;
template <typename C> static two test(...);
public:
enum { value = sizeof( test<T>(&set)) == sizeof(one) };
};
int main()
{
std::cout << setter_is_implemented<Foo>::value << std::endl;
std::cout << setter_is_implemented<Bar>::value << std::endl;
std::cout << setter_is_implemented<Fuu>::value << std::endl;
}
GCC错误消息
Test.cpp:24:66: error: ‘c’ was not declared in this scope
template <typename C> static one test( C c, SetterFunction = c ) ;
^
Test.cpp: In instantiation of ‘class setter_is_implemented<Foo>’:
Test.cpp:33:44: required from here
Test.cpp:28:35: error: address of overloaded function with no contextual type information
enum { value = sizeof( test<T>(&set)) == sizeof(one) };
^
Test.cpp: In instantiation of ‘class setter_is_implemented<Bar>’:
Test.cpp:34:44: required from here
Test.cpp:28:35: error: address of overloaded function with no contextual type information
Test.cpp: In instantiation of ‘class setter_is_implemented<Fuu>’:
Test.cpp:35:44: required from here
Test.cpp:28:35: error: address of overloaded function with no contextual type information
答案 0 :(得分:1)
AFAIK,在重载解析之前发生重载函数的地址,因此SFINAE无法以这种方式工作。这也更难,因为你的函数返回void(否则,只会检查结果的大小)。我的C ++ 03元编程很生疏,但这应该有效( live on coliru ):
namespace setter_is_implemented_detail {
struct dummy1 { char c[2]; };
typedef char dummy2;
dummy2 operator,(dummy1, dummy1);
template<typename T> dummy1 set(T const&,...);
template <typename T>
struct impl
{
typedef void (T::*FT)( const char* );
static T& x;
enum { value = sizeof( set(x,static_cast<FT>(0),static_cast<const char*>(0)), dummy1() ) != sizeof(dummy2) };
};
}
template <typename T>
struct setter_is_implemented: setter_is_implemented_detail::impl<T>{};
请注意以下几点:
set()
(根据您的问题描述,这不是什么大问题)(*)sizeof(void)
,因此可以简化代码static T&
)。如果你需要的话,它可以工作...... (*)请注意,这不适用于每个可能的set()
重载;对于任何一个sfinae都是如此,即使在c ++ 17中,set()
也必须总是对sfinae友好才能工作。
如果你需要完全匹配sfinae友好的set()重载,它仍然可以做到,但它更复杂;我分两个阶段进行:首先使用上面的代码找到可能的候选者,然后检查函数指针转换,就像在原始代码中一样。
(**)这个技巧有效,因为如果set()
具有void
返回类型(因此存在),则逗号始终被解释为内置逗号运算符(请参阅 c ++ 03 [3.9.1 / 9]:&#34; void类型的表达式只能用作表达式语句(6.2),作为逗号表达式的操作数[...]&#34; )导致最右边的表达。否则,使用虚拟集和逗号运算符。