DenverCoder21
DenverCoder21

Reputation: 887

Using std::enable if for template with 3 generic arguments

I've already found a few threads to the topic of std::enable_if, but unfortunately I am not able to apply the examples to my code.

template<class From, class To, class Value>
struct convert
{
  static Value apply(Value value)
  {
    return value;
  }
};

I want this to be active only when From and To are the same, so I tried to use

std::enable_if<std::is_same<From,To>::value>::Value

But that doesn't work. How would I do this?

I also have these two specializations, to give you a better picture of my problem:

template<class From, class Value>
struct convert<From, kilometer, Value>
{
  static Value apply(Value value)
  {
    doSomething;
  }
};

template<class To, class Value>
struct convertImpl <kilometer, To, Value>
{
  static Value apply(Value value)
  {
    doSomethingElse;
  }
};

This is where my abguity problems come from. Right now I'm static_asserting the case that From and To are the same thus making the code to compile. But I would like to just return the value when those two are of the same type.

Upvotes: 1

Views: 145

Answers (2)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48467

template<class From, class To, class Value>
struct convert
{
    template <typename F = From, typename T = To>
    static auto apply(Value value) -> typename std::enable_if<std::is_same<F,T>::value, Value>::type
    {
        static_assert(std::is_same<F, From>::value && std::is_same<T, To>::value, "");
        // no conversion
        return value;
    }

    template <typename F = From, typename T = To>
    static auto apply(Value value) -> typename std::enable_if<!std::is_same<F,T>::value, Value>::type
    {
        static_assert(std::is_same<F, From>::value && std::is_same<T, To>::value, "");
        // do conversion
        return value;
    }
};

DEMO

Alternatively this can be implemented using a tag-based dispatching:

template<class From, class To, class Value>
struct convert
{
    static Value apply(Value value)
    {
        using tag = std::integral_constant<bool, std::is_same<From, To>::value>; 
        return _apply(value, tag{});
    }

private:
    static Value _apply(Value value, std::true_type)
    {
        // no conversion
        return value;
    }

    static Value _apply(Value value, std::false_type)
    {
        // do conversion
        return value;
    }
};

DEMO 2

Upvotes: 3

WhozCraig
WhozCraig

Reputation: 66224

I don't think you want SFINAE for this, from your description I think you just want a specialization:

template<class From, class To, class Value>
struct convert
{
    static Value apply(Value value)
    {
        Value somethingElse = ...;
        return somethingElse;
    }
};

template<class From, class Value>
struct convert<From,From,Value>
{
    static Value apply(Value value)
    {
        return value; // SAME
    }
};

I admit I honestly don't see the sense in this, as Value is an independent type from both From and To, but you probably know something about it which I don't. It would seem this is your desire if you want the full struct specialized. See it live.

Best of luck

Upvotes: 4

Related Questions