0

I'm having trouble wrestling with C++'s syntax for template specializations outside of the class definition. I have this class:

template <class T>
class Foo     {
public:
    template <int U> 
    std::string bar();
private: 
    T m_data;
};

How can I specialize bar() for any T and a specific U?

I was expecting:

template <class T> template <>
std::string Foo<T>::bar<1>() {
    return m_data.one;
}

But I get:

error: invalid explicit specialization before ‘>’ token
template <class T> template <>
                             ^
error: enclosing class templates are not explicitly specialized

I could also try:

template <class T> template <int>
std::string Foo<T>::bar<1>() {
    return m_data.one;
}

but then I get:

error: non-class, non-variable partial specialization ‘bar<1>’ is not allowed
 std::string Foo<T>::bar<1>() {
                            ^
Stewart
  • 4,356
  • 2
  • 27
  • 59
  • That's impossible without specializing the class template as well. – Yola Mar 30 '18 at 09:54
  • I got a little more specific in my question. Here, I'm trying to ensure that type `T` has a member `.one` only if I call `Foo::bar<1>`. Is there another way to do a compile-time-check to confirm this? – Stewart Mar 30 '18 at 09:57

1 Answers1

1

Based on this answer:

template <typename T>
class has_one
{
    template <typename C> static char test(decltype(&C::one));
    template <typename C> static long test(...);

public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
}; 

template <class T>
class Foo {
public:
    template <int U>
    enable_if_t<U != 1 || U == 1 && has_one<T>::value, std::string> bar() {
        return m_data.one;
    }

private:
    T m_data;
};

struct Tone { std::string one; };
int main()
{
    Foo<int> f;
    f.bar<1>(); // This causes compile-time error
    Foo<Tone> f2;
    f2.bar<2>();
}
Yola
  • 18,496
  • 11
  • 65
  • 106
  • 1
    Thanks, this got me what I needed. Actually, I was able to simplify a bit. By using std::enable_if, I was able to do the specialization. I didn't end up using the `has_one` class because I would get a compiler error either way (which is good), and the compiler error generated without `has_one` is actually a little clearer in that it says that `class T` doesn't have member `one`. So I'll stick with using just the `enable_if` unless there is a reason not to. – Stewart Mar 30 '18 at 11:02