template<typename T>
struct rm_const_volatile {
using type = T;
};
// Call this (partial)specialization as "1"
template<typename T>
struct rm_const_volatile<const T> {
// remove topmost const and recurse on T
using type = typename rm_const_volatile<T>::type;
};
// Call this (partial)specialization as "2"
template<typename T>
struct rm_const_volatile<volatile T> {
// remove topmost volatile and recurse on T
using type = typename rm_const_volatile<T>::type;
};
I had defined the remove const volatile qualifier template meta-program as above.
Logically, when I write rm_const_volatile<const volatile int>
, my expectation is that compiler will evaluate in the following order:
Case 1:
rm_const_volatile<const volatile int>
rm_const_volatile<volatile int>
rm_const_volatile<int>
int
(final result).Case 2:
rm_const_volatile<volatile const int>
rm_const_volatile<const int>
rm_const_volatile<int>
int
(final result).So in my view above template specialization and general definition suffices to remove any const volatile qualifiers.
Cut the actual behavior errors out as ambiguous template instantiation.
// In main() below two calls are present (refer cpp.sh link below mentioned for full code)
----
std::cout << "Is volatile const int integral type with rm_const_volatile: " << is_integral<rm_const_volatile<volatile const int>::type>::value << std::endl;
std::cout << "Is const volatile int integral type with rm_const_volatile: " << is_integral<rm_const_volatile<const volatile int>::type>::value << std::endl;
-------
In function 'int main()':
54:132: error: ambiguous class template instantiation for 'struct rm_const_volatile<const volatile int>'
26:8: error: candidates are: struct rm_const_volatile<const T>
31:8: error: struct rm_const_volatile<volatile T>
54:95: error: incomplete type 'rm_const_volatile<const volatile int>' used in nested name specifier
54:95: error: incomplete type 'rm_const_volatile<const volatile int>' used in nested name specifier
54:138: error: template argument 1 is invalid
When I add following template specialization, everything works fine.
template<typename T>
struct rm_const_volatile<const volatile T> {
using type = T;
};
Please refer to this link for the full code.
I would like to know why the compiler reports template instantiation as ambiguous, when clearly it can chop off the top most qualifier and recursively instantiate to the final result as I have mentioned in the case 1 & 2 above.
Highly appreciate your valuable inputs and my sincere thanks for your time.
I would like to know why the compiler reports template instantiation as ambiguous
C++ considers const volatile int
and volatile const int
to be the same type. They are interchangable and mean the same thing.
Some other ways to spell this one type:
int const volatile
int volatile const
const int volatile
volatile int const
That said, C++ will never change overload rules based on the way you choose to spell a particular type.
Therefore, the template specializations <const T>
and <volatile T>
are both equally specialized for <const volatile int>
. Neither qualifier takes priority over the other.