I'm trying to create an addition operator for a custom template class, where the first argument is allowed to be either an instance of my class or a basic numeric type. My operator has a definition similar to the example code below:
#include <type_traits>
template<typename T>
struct MyTemplateStruct {
T val;
};
template<typename T, typename U>
struct MyCommonType {
typedef std::common_type_t<T, U> type;
};
template<typename T, typename U>
using MyCommonTypeT = typename MyCommonType<T, U>::type;
template<typename T, typename U>
MyTemplateStruct<MyCommonTypeT<T, U>> operator (
MyTemplateStruct<T> const& a, MyTemplateStruct<U> const& b)
{
return { a.val b.val };
}
template<typename T, typename U>
MyTemplateStruct<MyCommonTypeT<T, U>> operator (
T const a, MyTemplateStruct<U> const& b)
{
return { a b.val };
}
int main()
{
MyTemplateStruct<double> a{ 0 }, b{ 0 };
a = a b;
return 0;
}
My expectation was that due to SFINAE, the compilation error that results from trying to instantiate the second operator definition with T = MyTemplateStruct<double>, U = double
would just exclude that template from the list of potential matches. However, when I compile, I'm getting the following error:
/usr/include/c /7/type_traits: In substitution of ‘template<class ... _Tp> using common_type_t = typename std::common_type::type [with _Tp = {MyTemplateStruct, double}]’:
main.cpp:18:38: required from ‘struct MyCommonType<MyTemplateStruct, double>’
main.cpp:31:39: required by substitution of ‘template<class T, class U> MyTemplateStruct<typename MyCommonType<T, U>::type> operator (T, const MyTemplateStruct&) [with T = MyTemplateStruct; U = double]’
main.cpp:40:13: required from here /usr/include/c /7/type_traits:2484:61: error: no type named ‘type’ in ‘struct std::common_type, double>’
If I directly utilize std::common_type_t
in the operator definition, instead of using my wrapper template MyCommonTypeT
, then SFINAE works as I expect and there is no error. How can I make the above code compile when I have to wrap the call to std::common_type
in another template?
CodePudding user response:
You need to make MyCommonTypeT<T, U>
(i.e. MyCommonType<T, U>::type
) itself invalid, it's not enough that std::common_type_t<T, U>
is invalid when declaring type
in MyCommonType
. For example you can specialize MyCommonType
, when MyTemplateStruct
is specified as template argument, type
is not declared.
template<typename T, typename U>
struct MyCommonType {
typedef std::common_type_t<T, U> type;
};
template<typename T, typename U>
struct MyCommonType<MyTemplateStruct<T>, U> {};
template<typename T, typename U>
struct MyCommonType<T, MyTemplateStruct<U>> {};