I'm having an issue with some template stuff that I've narrowed down to the following example (C++17):
template <typename T> struct item {
operator item<const T> () const { return item<const T>(); }
};
void conversionToConstRefWorks (const item<const int> &) { }
template <typename T>
void butNotWhenTemplated (const item<const T> &) { }
int main () {
item<int> i;
item<const int> ci;
// these all compile fine:
conversionToConstRefWorks(ci);
conversionToConstRefWorks(i);
butNotWhenTemplated(ci);
// but this one fails:
butNotWhenTemplated(i);
}
In that example:
item<T>
has an implicit conversion operator toitem<const T>
, and- The conversion seems to work in
conversionToConstRefWorks()
, but - The conversion seems to be missed in
butNotWhenTemplated()
, where anitem<const int>
can be passed just fine but passing anitem<int>
fails to compile.
Compilation of that example fails (GCC 9.3) with:
g++ --std=c++17 -W -Wall -pedantic -Wno-unused-variable const_interop.cpp -o const_interop
const_interop.cpp: In function ‘int main()’:
const_interop.cpp:54:24: error: no matching function for call to ‘butNotWhenTemplated(item<int>&)’
54 | butNotWhenTemplated(i);
| ^
const_interop.cpp:40:6: note: candidate: ‘template<class T> void butNotWhenTemplated(const item<const T>&)’
40 | void butNotWhenTemplated (const item<const T> &) {
| ^~~~~~~~~~~~~~~~~~~
const_interop.cpp:40:6: note: template argument deduction/substitution failed:
const_interop.cpp:54:24: note: types ‘const T’ and ‘int’ have incompatible cv-qualifiers
54 | butNotWhenTemplated(i);
| ^
The root error seems to be:
types ‘const T’ and ‘int’ have incompatible cv-qualifiers
I understand what that means in a literal sense, but I don't understand why it is happening. My expectation is that the item<int> :: operator item<const int> () const
conversion operator would be applied when calling butNotWhenTemplated(i)
just as it was applied when calling conversionToConstRefWorks(i)
, and that int
would be selected for T
.
My main question is: Why isn't this compiling?
My other question is: For reasons outside the scope of this post, butNotWhenTemplated
has to be a template and has to specify <const T>
to all item
parameters, and I can't explicitly specify template parameters when calling it. Is there a way to make this work with those constraints?
Here it is on ideone (GCC 8.3).
Item<T>
I useT*
) – Overscrupulousint *
→int const * const &
conversion isn't done within a template parameter (unlikeItem<T>
→Item<const T>
-- yours is more similar in spirit toItem<T>
→const Item<T>
). E.g.T
andconst T
are the same type differing only in cv qualifiers, whereasItem<T>
andItem<const T>
are completely different types since the template parameters are different, and then something about the deduction rules let that be ok. Maybe. Otoh I have no idea what I'm talking about. – Karrykarst