0

I have this class:

template <typename T>
class Value {
    private:
    bool fixed;
    union {
        T value;
        std::function<T()> get;
    };

    public:
    Value(const T& value);
    template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
    Value(F&& get);
    Value(const T* pointer);
    ~Value();
    operator T();
};

I initially wrote it all on a header file but am now transfering the code to a .cpp file. The problem is I don't know how to include the typename = std::enable_if_t<std::is_invocable_v<F>> part when defining Value(F&& get).

First, I tried:

template <typename T>
template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
Value<T>::Value(F&& get) : fixed(false), get(std::forward<F>(get)) {}

which produced the error:

error: a default template argument cannot be specified on the declaration of a member of a class template outside of its class

Then, after reading this answer, I tried:

template <typename F>
std::enable_if_t<std::is_invocable_v<F>>
Value<T>::Value(F&& get) : fixed(false), get(std::forward<F>(get)) {}

which results in:

error: return type may not be specified on a constructor

What should I do instead?

cabralpinto
  • 1,814
  • 3
  • 13
  • 32
  • 5
    Does this https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file#:~:text=Templates%20must%20be%20used%20in,several%20versions%20of%20that%20code. answer your question indirectly? – Slava Dec 07 '20 at 18:43
  • Just leave out the default argument in the definition. But are you sure you want to move a template to a `.cpp` file? In general it's not a good idea. – super Dec 07 '20 at 19:16
  • @super I believe they are going to `#include` the `.cpp` file inside the header. Could that be harmful for a single `template` class? – Cem Dec 07 '20 at 19:26
  • 1
    @Cem Just confusing. If you are going to have the definitions in the header file, splitting it into a `.cpp` and including it just will make both people reading the code and some static analysis tools etc left wondering what's going on. I have seen people do that, but then they usually name the file `.tpp` or something to show that it's not a compilation unit. – super Dec 08 '20 at 10:24

1 Answers1

1
    template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
    Value(F&& get);

Here, std::enable_if_t<std::is_invocable_v<F>> is a default template argument (default value of the second template argument) and you have already specified it in the declaration inside the class. So, when you add an implementation outside the class, you should omit the default value:

template <typename T>
template <typename F, typename>
Value<T>::Value(F&& get) : fixed(false), get(std::forward<F>(get)) {}

This is indeed what the error says: a default template argument cannot be specified on the declaration of a member of a class template outside of its class

Cem
  • 1,276
  • 4
  • 17