I have a template class with a constructor in which I want to explicitly forbid the usage of any type beyond a well defined list, like this:
template<typename Anything>
class MyClass
{
public:
MyClass(int &);
MyClass(float &);
MyClass(Anything &) = delete;
}
However, since the code for the integer and the double version are identical, and only differ in the type, I'd like to define it using the templatized version, such as:
template<typename Anything>
MyClass<Anything>::MyClass(Anything &var)
{
/* Code that operates over var */
...
}
instead of virtually having to duplicate the code for both valid constructors.
However, when I tried to do so, I get:
error: redefinition of 'MyClass<Anything>::MyClass(Anything&)'
It works by removing the "= delete".
Is there a way to use the template to define the function but without explicitly allowing to receive more types than the ones also explicitly described?
I checked How can I prevent implicit conversions in a function template? and also Why can I prevent implicit conversions for primitives but not user-defined types?, but their issues don't seem to be equivalent to the current one.
Thanks a lot.
UPDATE: Using gcc-4.8.5, it works!!! Even with the = delete keyword included.
The problem with your definition is that you're trying to implement the exact function that you have marked with = delete
.
You actually want another function template that works with both int
and float
. You can achieve that by first defining an IntOrFloat
predicate:
template <typename T>
using IntOrFloat = std::bool_constant<
std::is_same_v<T, int> || std::is_same_v<T, float>>;
Then you can define two unambiguous constructors that use std::enable_if_t
to check whether or not the predicate is fulfilled by the type passed in by the user:
class MyClass
{
public:
template <typename T,
std::enable_if_t<IntOrFloat<T>{}>* = nullptr>
MyClass(T&);
template <typename Anything,
std::enable_if_t<!IntOrFloat<Anything>{}>* = nullptr>
MyClass(Anything&) = delete;
};
Usage example:
int main()
{
int v0 = 0;
float v1 = 0.f;
const char* v2 = "igijsdg";
MyClass x0{v0}; // OK
MyClass x1{v1}; // OK
MyClass x2{v2}; // Error
}