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).