I was writing a simple type based dispatcher using unnamed parameter, which is a pretty normal thing I guess.
When it came to actually call the function, I wanted to pick up the overload with out having any variable at hand. Is it possible?
E.g.
void f1(int /*can change the type*/) {
}
int main(int, char*) {
f1(/*what to put here?*/);
return 0;
}
My "real" example was a simple type-based dispatcher. Best what I came up with was a pointer as the unnamed parameter, I think it has least overhead possible:
#include <iostream>
using namespace std;
template<typename U>
class A {
public:
A(const U& u) : u(u) {};
template <typename T>
T get_as() {
T* t; // <- ugly
return get(t);
}
U get(U*) {
return u;
}
int get(int*) {
return i;
}
double get(double*) {
return d;
}
private:
U u;
int i = 5;
double d = 3.14;
};
int main() {
A<string> a("name");
cout << a.get_as<double>() << '\n';
cout << a.get_as<int>() << '\n';
cout << a.get_as<string>() << '\n';
return 0;
}
I guess it's purely aesthetic with a pointer, because it's probably optimized, but still I wonder. I also guess this might be impossible, because (AFAIK) this argument goes through stack. So technically there is always this "overhead". Is this right?
Not sure if this should be another question, but is there a way to express, "just pick up this overload" with out trickery?
PS. I figured out I could use T*(0)
in the "ugly" line, but it's probably even less readable.
You can't get any clearer or more efficient than passing an empty tag struct:
template<class T> struct tag {};
double get(tag<double>) {
return d;
}
template <typename T>
T get_as() {
return get(tag<T>{});
}
An advantage over using pointer types for dispatch is that there's no danger of accidentally indirecting the passed-in null pointer.
(Aside: What happens to empty classes in the AMD64 ABI? - but your calls will usually be inlined.)
Since you are talking about "aesthetics", I'm wondering if this may help you:
Live Demo
template<typename U>
class A
{
public:
static_assert(!std::is_same<int, U>::value && !std::is_same<double,U>::value,
"Template argument cannot be <int> or <double>.");
A(const U& u) : u(u) {};
explicit operator U() { return u; }
explicit operator int() { return i; }
explicit operator double() { return d; }
private:
U u;
int i = 5;
double d = 3.14;
};
int main()
{
A<string> a("wow");
cout << double(a) << '\n';
cout << int(a) << '\n';
cout << string(a) << '\n';
return 0;
}
I think user-defined conversion operators are not evil if they are explicit.
You cant use them by "mistake". Also, this class should have no overhead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With