3

Is it possible in C++ to use some sort of identifiers akin to function arguments to overload functions? This would allow easier use with templates. It would also make the code look nicer for my particular case, which I'm not explaining in detail.

In case that didn't make much sense, and I honestly don't even know the right keywords for this (please let me know), here's a toy example:

I want writing something like this

function(i);
function(special_action);
function(special_action_2);

being understood like this

function(i);
function_special_action();
function_special_action_2();

What is the best way of achieving this? So far, I have tried doing dummy enums like this:

// normal action
void function(int i) { ... }

// special actions
enum dummy_enum_for_special_action { special_action };
void function(const dummy_enum_for_special_action & dummy) { ... }

I'm guessing the parameter passing will be optimized away by the compiler. Is there, however, a better way of doing this?

Toni Makkonen
  • 131
  • 1
  • 5

2 Answers2

3

This is know as “tag dispatch” and it’s a pretty common technique with libraries that offer generic functions (such as the standard <algorithms> library).

Just use separate tag types for the parameters:

struct i { }; // bad name.
struct special_action { };
struct special_action_2 { };

Function declarations:

void function(i) { … }
void function(special_action) { … }
void function(special_action_2) { … }

And call like this:

function(i());
function(special_action());
function(special_action_2());

Alternatively, if you want to get rid of the parentheses, use global instances (but I’m not sure that’s a good idea);

namespace { // See comment below
    struct i_t { } i;
    // etc …
}

void function(i_t) { … }
// etc …

The unnamed namespace is necessary to avoid violating the one definition rule for the variable names declared at global scope.

Community
  • 1
  • 1
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • `static struct i_t {} i;` works better. Oh, and another approach is `function()`, where you `template` and specialize the function, and have it then use whatever dispatching mechanisms it wants in the specializations. – Yakk - Adam Nevraumont Jul 15 '13 at 13:32
  • @Yakk Isn’t that kind of deprecated though? (Not officially, but in usage. EDIT: officially! §7.3.1.1/2) But true, I need *some* mechanism to satisfy ODR, so either `static` or anonymous namespaces. – Konrad Rudolph Jul 15 '13 at 13:34
2

you can use a series of dummy types for "tagging" the different functions. Here's an example

#include <iostream>

using namespace std;

template <typename tag>
void func(const tag&);

struct First{};
First first;

template <>
void func(const First&){
    cout << "funcFirst" << endl;
}

struct Second{};
Second second;

template <>
void func(const Second&){
    cout << "funcSecond" << endl;
}

struct Third{};
Third third;

void func(const Third&){
    cout << "funcThird" << endl;
}

int main()
{
    func(first);
    func(second);
    func(third);
}

which you can try here.

Of course, I suggest you to use proper namespaces, as to avoid problems with such global definitions, i particular for what concerns "first" and "second" (in my example).

Notice that you don't even need to make the function a template, this is just one possibility. You can rely on simple overloading, as in func(const Third&).

Stefano Falasca
  • 8,837
  • 2
  • 18
  • 24