1

Using c++14, I have some function declarations that resemble the following.

template <class... Args>
struct potato {
template <class T, class = std::enable_if_t<!std::is_same<T, int>::value>>
const T& blee(size_t blou) const;

template <class T, class = std::enable_if_t<std::is_same<T, int>::value>>
const T& blee(size_t blou) const;
};

Is it possible to implement the functions separately? From what I can tell, there is no way the compiler can figure out what is implementing what. For example :

template <class... Args>
template <class T, class>
const T& potato<Args...>::blee(size_t blou) const {
    // do something
}

template <class... Args>    
template <class T, class>
const T& potato<Args...>::blee(size_t blou) const {
    // do something
}

The enable_if information is lost at that point. Am I missing a trick in my toolbag to make this work? Note that I'd rather not use return type enable_if or argument enable_if as they are ungodly.

edit : Updated to represent my use-case better.

scx
  • 3,221
  • 1
  • 19
  • 37
  • Why don't you use tag dispatch? – SergeyA Nov 08 '18 at 15:44
  • Whomever posted the question has already been answered, that is not true. The linked question doesn't even use declaration and implementation seperately. – scx Nov 08 '18 at 15:50
  • 2
    So, your actual question is how to define an out of line function that uses SFINAE, right? – NathanOliver Nov 08 '18 at 15:55
  • @NathanOliver Yes :) – scx Nov 08 '18 at 16:00
  • 1
    Then this is basically a dupe of [this](https://stackoverflow.com/questions/48480469/function-implementation-with-enable-if-outside-of-class-definition) or [this](https://stackoverflow.com/questions/43818137/is-out-of-line-sfinae-on-template-member-functions-possible) – NathanOliver Nov 08 '18 at 16:04
  • @NathanOliver Ah, yes absolutely. Thanks for pointing out the correct dupes! – scx Nov 08 '18 at 16:05

2 Answers2

2

You don't really need enable_if for that:

template<class T>
const T& blee(size_t blou) const {
    // do something
}

template<>
const int& blee<int>(size_t blou) const {
    // do something
}

Edit: since your functions are inside a class template, you will have to use tag dispatching:

template<class... Args>
struct potato {
    template<class T>
    void blee() const;

private:
    void realBlee(std::true_type) const;
    void realBlee(std::false_type) const;
};

template<class... Args>
template<class T>
void potato<Args...>::blee() const {
    realBlee(std::is_same<T, int>());
}

template<class... Args>
void potato<Args...>::realBlee(std::true_type) const {
    std::cout << "int\n";
}
template<class... Args>
void potato<Args...>::realBlee(std::false_type) const {
    std::cout << "generic\n";
}

Live on Coliru

or something similar, like a constexpr if:

template<class... Args>
struct potato {
    template<class T>
    void blee() const;

private:
    void intBlee() const;
};

template<class... Args>
template<class T>
void potato<Args...>::blee() const {
    if constexpr (std::is_same_v<T, int>) {
        intBlee();
    } else {
        std::cout << "generic\n";
    }
}

template<class... Args>
void potato<Args...>::intBlee() const {
    std::cout << "int\n";
}

Live on Coliru

Nelfeal
  • 12,593
  • 1
  • 20
  • 39
0

The enable_if information is lost at that point.

It is not lost, it is int in both cases. Just one template is not being instantiated.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271