2

I'm writing a templated singleton superclass, that can provide a thread-local instance or a process-global instance. The code below compiles and technically fits my need. But, how can I write the function implementation outside of the class declaration? How do I declare the function in the class (is the commented line right)?

All similar questions implement the function in the class declaration.

#include <vector>
#include <type_traits>


using namespace std;

template <class t, bool tls=true>
class A{
public:
  typedef std::vector<t> Avector;
//  static Avector& getVector();

  template <class T=t, bool TLS=tls, typename std::enable_if<!TLS>::type* = nullptr>
  static Avector&
  getVector(){
    static Avector v=Avector();
    return v;
  }

  template <class T=t, bool TLS=tls, typename std::enable_if<TLS>::type* = nullptr>
  static Avector&
  getVector(){
    static thread_local Avector v=Avector();
    return v;
  }
};

int main(){
  vector<int>& vi = A<int>::getVector();
  vector<double>& vd = A<double, false>::getVector();
  return 0;
}
Joachim
  • 71
  • 6
  • Instead of SFINAE on the TLS bool, just use the bool directly and specialize for true and false. – rubenvb Jun 09 '17 at 14:27
  • @rubenvb You can't partially specialize a function, although from the code above, I don't see why the function are templates – Passer By Jun 09 '17 at 14:48
  • Right, then you use helper structs like you did in your answer ;) – rubenvb Jun 09 '17 at 15:10
  • The advantage of using SFINAE in this case is, that I can use the same class A for thread-local and per-process instances. The posted code is just a minimal reproducer. The actual class A in my application provides more methods. – Joachim Jun 10 '17 at 11:29

2 Answers2

1

You can instead write

template<typename T, bool>
struct A
{
    typedef std::vector<T> Avector;
    static Avector& getVector();
};

template<typename T, bool b>
typename A<T, b>::Avector& A<T, b>::getVector()
{
    thread_local typename A<T, true>::Avector v;
    return v;
}

template<typename T>
class A<T, false>
{
    typedef std::vector<T> Avector;
    static Avector& getVector();
};

template<typename T>
typename A<T, false>::Avector&  A<T, false>::getVector()
{
    static typename A<T, false>::Avector v;
    return v;
}

Also, generally singletons shouldn't be used

Passer By
  • 19,325
  • 6
  • 49
  • 96
  • My question was, how to implement the function outside of the class declaration. This answer again implements the function in the declaration. Further, my real code has more functions and with above approach, I can aviod code duplication. – Joachim Jun 09 '17 at 18:16
  • @Joachim Do you mean what the syntax is for defining the method outside the class? – Passer By Jun 10 '17 at 06:19
  • Yes, I couldn't find the syntax to define the methods in my code outside of the class declaration. – Joachim Jun 10 '17 at 11:24
0

I was searching an answer, and we got one on Stack Overflow 2 years after you posted your question, here : How to use std::enable_if on method of templated class with seperate declaration and definition via specialization.

  1. First, you have to redefine the method as a template, with another typename, and with default value the class's template.
  2. Second, you have to template<> 2 times on the implementation's side.
// hpp
template<typename T>
class A {
    template <class U=T, typename std::enable_if_t<myCondition, bool>>
    void myMethod();
}
// cpp
template<typename T>
template <class U=T, typename std::enable_if_t<myCondition, bool>>
void A::myMethod() {
    // ...
}

If you don't want to define another template parameter, you can define the restriction as return type. Here we changed bool by void, but it can be whatever you want :

// hpp
template<typename T>
class A {
    typename std::enable_if_t<myCondition, void>
    myMethod();
}
// cpp
template<typename T>
typename std::enable_if_t<myCondition, void>
A::myMethod() {
    // ...
}
NoxFly
  • 179
  • 1
  • 12