Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to "pass" an unnamed parameter with out creating a temporary variable?

Tags:

c++

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.

like image 378
luk32 Avatar asked Mar 13 '23 19:03

luk32


2 Answers

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

like image 200
ecatmur Avatar answered Mar 15 '23 09:03

ecatmur


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.

like image 37
Jts Avatar answered Mar 15 '23 08:03

Jts