I have a C++ function template:
#include <string_view>
template<typename T>
T get_gadget(std::string_view str);
I also added explicit specializations for some user-defined types, e.g., GadgetA and GadgetB:
template<>
GadgetA get_gadget<GadgetA>(std::string_view str) {
// implementation
}
template<>
GadgetB get_gadget<GadgetB>(std::string_view str) {
// implementation
}
Now, I want to make it work for a Wrapper type like this:
template<typename T>
Wrapper<T> get_gadget(std::string_view str) {
auto underlying = get_gadget<T>(str);
// implementation
}
However, when I compile, I get an ambiguous call error. I think this happens because the compiler cannot distinguish between the primary template and the Wrapper specialization.
I would like to solve this using concepts or template metaprogramming, without using void pointers, tag dispatching, or unnecessary boilerplate.
#include <iostream>
#include <string_view>
// Primary template (only declared)
template<typename T>
T get_gadget(std::string_view str);
// --- Some user-defined types ---
struct GadgetA {
std::string name;
};
struct GadgetB {
int value;
};
// --- Explicit specializations ---
template<>
GadgetA get_gadget<GadgetA>(std::string_view str) {
return GadgetA{std::string(str)};
}
template<>
GadgetB get_gadget<GadgetB>(std::string_view str) {
return GadgetB{static_cast<int>(str.size())};
}
// --- A generic Wrapper ---
template<typename T>
struct Wrapper {
T inner;
};
// --- Generic overload for Wrapper<T> ---
template<typename T>
Wrapper<T> get_gadget(std::string_view str) {
auto underlying = get_gadget<T>(str); // delegate
return Wrapper<T>{underlying};
}
// --- Demo ---
int main() {
auto a = get_gadget<GadgetA>("HelloA");
auto b = get_gadget<GadgetB>("HelloB");
auto wa = get_gadget<Wrapper<GadgetA>>("WrappedA");
std::cout << "GadgetA: " << a.name << "\n";
std::cout << "GadgetB: " << b.value << "\n";
std::cout << "Wrapper<GadgetA>: " << wa.inner.name << "\n";
}
Tor the one that returnsWrapper<T>when you callget_gadget<Foo>? Forget about templates for a moment, then you are trying to overload based on return type alone, which is not possibleWrapper<T> get_gadget(std::string_view str)would work, thenauto underlying = get_get_gadget<T>(str);would just recursively call the same function again and again without end