I want to define 2 default constructors one for each type of the template parameter CharT with the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
template<typename CharT>
class MyString : public ObjectCounter<MyString<CharT>> {
CharT* pT;
public:
template<typename U = std::enable_if_t<std::is_same<CharT, char>::value>>
MyString()
{
pT = "hello";
}
template<typename U = std::enable_if_t<std::is_same<CharT, wchar_t>::value>>
MyString()
{
pT = L"hello";
}
};
but it does not compile. I get these errors in VStudio 2017:
[comment]
error C2535: 'MyString<CharT>::MyString(void)': member function already defined or declared
error C2535: 'MyString<char>::MyString(void)': member function already defined or declared
// and others similar
[/comment]
enable_if affects overload resolution - it doesn't let you ignore the one-definition rule. Note that both constructors have the same signature: default template arguments don't affect that.
The dummy parameters to f_impl() are used to disambiguate the two overloads.
Since it's the constructor's body which has to change, I think it's fine to use the same technique, although I would be wary of overloading constructors with dummy arguments directly. I would tend towards CRTP or even a class specialization if that was necessary.
1. For the templated constructors, the type U can't be deduced; so fixing the enable_if won't solve the problem.
2. In any case, these would (should) be errors: pT = "hello"; or pT = L"hello";
(no conversion from string literal to char/wchar_t* - the const qualifier can't be dropped)
Thanks to both of you. So, there is no way to have 2 functions with same signature that are implemented differently based on the actual template argument? Why is this? I know that the one definition rule is there, but if in each instantiation only one of the 2 functions would be instantiated there would not be a violation of the ODR.
The std::enable_if is only evaluated when the constructor call is compiled, since it involves a template that's only available at that point. At class definition you still have two functions with the same signature.
If you just want to do different things based on T you could use an if inside the constructor. Since the if predicate can be computed at compile time, the if could get simplified into unconditional code.
> if in each instantiation only one of the 2 functions would be instantiated
> there would not be a violation of the ODR.
True.
But,
Notes
A common mistake is to declare two function templates that differ only in their default template arguments. This is illegal because default template arguments are not part of function template's signature, and declaring two different function templates with the same signature is illegal. http://en.cppreference.com/w/cpp/types/enable_if
This (delightfully convoluted) version is fine.
The function templates have different signatures; and SFINAE will eliminate all but one of them: