Just because the if-branch is never entered doesn't mean the code within the branch can be invalid. (Another way to think about it: you aren't guaranteed anything about optimizations, yet your code would only be valid with a dead-branch optimization.)
What you do is shift the branch to a function. Typically you have a framework like this:
// 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
Then something like this:
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
}
It's good practice to have to meta-functions inherit from the correct bool_type
, to ease use:
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
{};
So it just becomes:
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>());
}