I'm trying to design a wrapper to tackle arithmetic params with some special logic.
https://godbolt.org/z/zG959e5Pz
#include <stdio.h>
template <class T>
struct wrapper {
wrapper(const T& o): value(o) {}
T value;
};
void func(wrapper<int> a) {
printf("int: %d\n", a.value);
}
int main () {
func(1); // int: 1
func(1.0); // int: 1
}
However, when I declare an overload function for func
, I meet a compile error. It seem that the compiler cannot choose a concrete overloaded func.
#include <stdio.h>
template <class T>
struct wrapper {
wrapper(const T& o): value(o) {}
T value;
};
void func(wrapper<int> a) {
printf("int: %d\n", a.value);
}
void func(wrapper<double> a) {
printf("double: %.2f\n", a.value);
}
int main () {
func(1);
// func(1.1);
}
https://godbolt.org/z/YEo4c3E69
the compiler error
<source>: In function 'int main()':
<source>:18:9: error: call of overloaded 'func(int)' is ambiguous
18 | func(1);
| ~~~~^~~
<source>:9:6: note: candidate: 'void func(wrapper<int>)'
9 | void func(wrapper<int> a) {
| ^~~~
<source>:13:6: note: candidate: 'void func(wrapper<double>)'
13 | void func(wrapper<double> a) {
| ^~~~
How can I fix it?
Make the constructor a template, accepting any type. Then reject types other than T
with SFINAE. This will prevent implicit argument conversions when calling it.
#include <concepts>
template <class T>
struct wrapper {
template <std::same_as<T> U = T>
wrapper(const U &o): value(o) {}
T value;
};
Or pre-C++20:
template <class T>
struct wrapper {
template <typename U = T, std::enable_if_t<std::is_same_v<T, U>, std::nullptr_t> = nullptr>
wrapper(const U &o): value(o) {}
T value;
};