Tom
Tom

Reputation: 7971

decltype comparison

Is there a way to compare the result of decltype in C++11?

In other words, why is this code invalid:

template<typename T, typename U>
void func(T& t, U& u) {
    if(decltype(t) == decltype(u)) {
        // Some optimised version for this case
    } else {
        // A more general case for differing types
    }
}

I know that in some cases this particular problem can be solved by partial template specialisation; my question is about comparison of decltypes.

Edit: The question came up in the course of trying to provide defaults for free functions through SFINAE. Perhaps a better question would have been why this is invalid:

template<bool B>
bool SomeFunction() { ... }

template<typename T, typename U>
bool SomeFunctionWrapper(T& t, U& u) {
    SomeFunction<decltype(t) == decltype(u)>();
}

I've since found another solution (that doesn't involve templates at all) but at one stage I tried this:

// If it exists, the free function is defined as
// bool AFreeFunction();
typedef struct { char } undefined;
template<typename T = void>
undefined AFreeFunction();

template<bool B>
bool AFreeFunctionWrapper_() {
    return false;
}

template<>
bool AFreeFunctionWrapper_<false>() {
    return AFreeFunction();
}

bool AFreeFunctionWrapper() {
    return AFreeFunctionWrapper_<decltype(AFreeFunction()) == decltype(undefined)>();
}

I eventually got a variant of this strategy working with GCC 4.6, but then discovered that default template arguments are not allowed for template functions in MSVC, even in the 2012 RC. So the eventual solution looks like this:

class AFreeFunction {
public:
    operator bool() { return false; }
};

If the function is defined, it gets called. If it's not, it is instead interpreted as a constructor for the class, which is then implicitly cast to bool.

Upvotes: 8

Views: 9481

Answers (3)

Xeo
Xeo

Reputation: 131809

You normally solve this problem through tag dispatching. Also, you already have the "declared type" of t and u - T& and U&, respectively. To compare types for equality, you can use std::is_same. However, overload resolution already solves this problem for you:

template<class T>
void f(T& v1, T& v2){ ... } // #1

template<class T, class U>
void f(T& t, U& u){ ... } // #2

#1 is more specialized than #2 if both arguments to f are of the same type. If you, for whatever reason, insist on solving this through manual type comparision, here's how it would look applying the before mentioned points:

#include <type_traits>

namespace detail{
template<class T, class U>
void f(T& t, U& u, std::true_type){ ... } // #1

template<class T, class U>
void f(T& t, U& u, std::false_type){ ... } // #2
} // detail::

template<class T, class U>
void f(T& t, U& u){
  detail::f(t, u, std::is_same<T,U>()); // tag dispatching
}

std::is_same will derive from std::true_type if both types are the same, and from std::false_type if not.

Upvotes: 10

ecatmur
ecatmur

Reputation: 157374

You can do this using SFINAE (std::enable_if):

template<typename T, typename U>
typename std::enable_if<std::is_same<T, U>::value, void>::type func(T& t, U& u) {
    std::cout << "same\n";
}
template<typename T, typename U>
typename std::enable_if<!std::is_same<T, U>::value, void>::type func(T& t, U& u) {
    std::cout << "different\n";
}

As Mehrdad says, decltype(t) and decltype(u) are types (T & and U & respectively), not values, so cannot be compared at value-expression level but must be compared at meta-expression (template) level.

Upvotes: 4

user541686
user541686

Reputation: 210525

Why is it invalid? The result of a decltype is, well, a type. So it's saying something like

if (int == int)

which the language obviously doesn't allow.

You'll need to separate the two parts of the function and put the specialized part inside a function in a specialized class, and forward the call there. It's painful.

Or, you could use typeid or run-time type information, if your implementation implements it correctly, although that will defer everything to when the program runs (which allows for fewer optimizations).

Upvotes: 6

Related Questions