我有一个SFINAE测试用于检查一个类是否有函数。测试工作正常,但是当我尝试在if语句中使用它时,我遇到编译器错误。
//SFINAE test for setInstanceKey()
template <typename K>
class HasSetInstanceKey
{
template <typename C>
static char test( typeof(&C::setInstanceKey) );
template <typename C>
static long test(...);
public:
enum { value = 1 == sizeof(test<K>(0)) };
};
我得到“错误:'类Node'在第二行没有名为'setInstanceKey'的成员”,即使else子句应该执行。
if ( 0 != HasSetInstanceKey<T>::value)
instance->setInstanceKey(instanceKey);
else
...
有没有办法让这项工作?
感谢。
答案 0 :(得分:3)
仅仅因为从未输入if分支并不意味着分支中的代码可能无效。 (考虑它的另一种方式:你不能保证任何关于优化的东西,但你的代码只有在死分支优化时才有效。)
您所做的是将分支转移到一个功能。通常你有这样一个框架:
// holds some integral constant
template <typename T, T V>
struct integral_constant
{
static const T value = V;
};
// holds a boolean constant
template <bool V>
struct bool_type : integral_constant<bool, V>
{};
typedef bool_type<true> true_type; // a true boolean constant
typedef bool_type<false> false_type; // a false boolean constant
typedef const true_type& true_tag; // tag a function as the true variant
typedef const false_type& false_tag; // tag a function as the false variant
然后是这样的:
namespace detail
{
template <typename T, typename KeyType>
void foo(T* instance, const KeyType& instanceKey, true_tag)
{
// we are in the true variant, so our meta-function's value was true
// therefore, instance has the ability to do setInstanceKey
instance->setInstanceKey(instanceKey);
}
template <typename T, typename KeyType>
void foo(T*, const KeyType&, false_tag)
{
// we are in the false variant, so our meta-function's value was false
// therefore, instance does not have the right capabilities,
// so do nothing
}
}
// interface, forwards to correct implementation function
template <typename T, typename KeyType>
void foo(T* instance, const KeyType& instanceKey)
{
// pass instance, but to the overloaded foo
// that accepts the right boolean result
detail::foo(instance, instanceKey, // plug the value into a bool_type,
bool_type<HasSetInstanceKey<T>::value>()); // and instantiate it
// will either go into the true_tag or false_tag
}
最好让元函数继承正确的bool_type
,以便于使用:
namespace detail
{
// implementation
template <typename K>
class HasSetInstanceKey
{
// note, using char and long doesn't necessarily guarantee
// they each have a unique size. do this instead:
typedef char yes[1];
typedef char no[2]; // these must have different sizes
template <typename C>
static yes& test( typeof(&C::setInstanceKey) );
template <typename C>
static no& test(...);
public:
// check against size of yes result
static const bool value = sizeof(test<K>(0)) == sizeof(yes);
};
}
template <typename K>
struct HasSetInstanceKey : // delegate to implementation, take result and
bool_type<detail::HasSetInstanceKey<K>::value> // inherit from the
// appropriate bool_type
{};
所以它变成了:
template <typename T, typename KeyType>
void foo(T* instance, const KeyType& instanceKey)
{
// because it inherits from bool_type, it can be implicitly
// converted into either true_tag or false_tag
detail::foo(instance, instanceKey, HasSetInstanceKey<T>());
}