Question

Consider the followint template:

template<class T>
void doStuff(const T& a)
    {
    if(std::is_copy_assignable<T>::value)
        {
        T x;
        x=a;
        printf("Hello\n");
        }
    else
        {
        printf("Goodbye\n");
        }
    }

This fails to compile even though the "Hello" part is never run for non-copy-assignable types. What should I do instead?

Was it helpful?

Solution

Here is a tag dispatch based way to solve your problem:

template<class T>
void doStuffHelper(const T& a, std::true_type can_copy_assign)
{
  T x;
  x=a;
  printf("Hello\n");
}
template<class T>
void doStuffHelper(const T& a, std::false_type can_copy_assign)
{
  printf("Goodbye\n");
}
template<class T>
void doStuff(const T& a)
{
  return doStuffHelper( a, std::is_copy_assignable<T>() );
}

here, only the version that works is compiled. The name of can_copy_assign exists merely for documentation -- the point is that I override based on std::is_copy_assignable<T>(), and I use override dispatch to pick which implementation I am going to use.

In your code, the if block becomes something like if(true). The else clause of an if block that is if(true) still has to compile, which means the methods used have to be valid, even though they will never run.

The tag dispatch solution arranges it so that functions with the expected properties are compiled with the code that uses the properties.

Similar methods involving SFINAE can be used, but SFINAE has some annoying complications that mean it is usually best to avoid it, if possible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top