Violet Giraffe
Violet Giraffe

Reputation: 33579

Using std::enable_if on template function return type to exploit SFINAE - compilation error

The following code

#include <type_traits>

struct CByteArray {};
struct HLVariant {
    HLVariant() {}
    HLVariant(const HLVariant&) {}
    HLVariant(const CByteArray&) {}

    };

template <typename T>
inline typename std::enable_if<!std::is_pod<T>::value, CByteArray>::type serialize(const T& value)
{
    return serialize(HLVariant(value));
}

template <typename T>
inline typename std::enable_if<std::is_pod<T>::value, CByteArray>::type serialize(const T& value)
{
    return CByteArray();
}

template <>
inline CByteArray serialize(const HLVariant& value)
{
    return CByteArray();
}

int main()
{
    serialize(0);
    serialize(CByteArray());
    serialize(HLVariant());

    return 0;
}

triggers a compilation error C2794: 'type' : is not a member of any direct or indirect base class of 'std::enable_if<false,CByteArray>' in MSVC 2013. It does, however, work in ideone: enter link description here

What's the mistake here?

The error is the same in MSVC 2010, 2012 and 2013.

Upvotes: 2

Views: 745

Answers (1)

Ben Hymers
Ben Hymers

Reputation: 26526

It looks ok to me, but I can fix it by removing the template<> from the final overload of serialize. No need to make it a full specialisation when a normal overload will do!

EDIT: What else works is providing a template specialisation which matches only HLVariant (and further restricting the other specialisations to no longer match HLVariant, to avoid ambiguity).

This should do it:

http://ideone.com/0UGkcn

#include <type_traits>
#include <iostream>

struct CByteArray {};
struct NonPod {public: int a; private: int b;};
struct HLVariant {
    HLVariant() {}
    HLVariant(const HLVariant&) {}
    HLVariant(const CByteArray&) {}
    HLVariant(const NonPod&) {}
};

template <typename T>
inline typename std::enable_if<std::is_same<T, HLVariant>::value && !std::is_pod<T>::value, CByteArray>::type serialize(const T& value)
{
    std::cout << "serialize non-pod variant\n";
    return CByteArray();
}

template <typename T>
inline typename std::enable_if<!std::is_same<T, HLVariant>::value && !std::is_pod<T>::value, CByteArray>::type serialize(const T& value)
{
    std::cout << "serialize non-pod non-variant\n";
    return serialize(HLVariant(value));
}

template <typename T>
inline typename std::enable_if<std::is_pod<T>::value, CByteArray>::type serialize(const T& value)
{
    std::cout << "serialize pod\n";
    return CByteArray();
}

int main()
{
    std::cout << "int:\n";
    serialize(0);
    std::cout << "CByteArray:\n";
    serialize(CByteArray());
    std::cout << "HLVariant:\n";
    serialize(HLVariant());
    std::cout << "NonPod:\n";
    serialize(NonPod());
}

Upvotes: 2

Related Questions