Диспетчеризация тегов в смешанных условиях выполнения / времени компиляции

У меня есть следующий код отправки тегов (см. LiveWorkSpace)

#include <iostream>

// traits types
struct A {}; struct B {}; struct C {};

// helpers
void fun_impl(bool, A) { std::cout << "A\n"; }
void fun_impl(bool, B) { std::cout << "B\n"; }

// would like to eliminate this
void fun_impl(bool b, C)
{
if(b)
fun_impl(b, A());
else
fun_impl(b, B());
}

template<typename T>
void fun(bool b, T t)
{
// T = A, B, or C
fun_impl(b, t);
}

int main()
{
fun(true,  A()); // "A"fun(false, A()); // "A"fun(true,  B()); // "B"fun(false, B()); // "B"fun(true,  C()); // "A"fun(false, C()); // "B"}

Однако эта диспетчеризация тега тесно связана с функцией fun и мне нужно сохранить 3 вспомогательные функции для реализации этой диспетчеризации тегов для каждой функции, которая использует это.

Аргумент вычета не удается: Я попытался абстрагировать fun_impl в параметр шаблона mixed_dispatch объект функции, но если я потом передам fun_impl в качестве аргумента невозможно определить, какая из двух перегрузок должна быть обязательной.

template<typename T>
struct mixed_dispatch
{
template<typename Fun>
void operator()(Fun f, bool b)
{
return f(b, T());
}
};

template<>
struct mixed_dispatch<C>
{
template<typename Fun>
void operator()(Fun f, bool b)
{
if (b)
return f(b, A());
else
return f(b, B());
}
};

template<typename T>
void fun(bool b, T)
{
// T = A, B, or C
mixed_dispatch<T>()(fun_impl, b); // ERROR: Fun cannot be deduced
}

Вопрос: есть ли какой-либо другой способ отделить диспетчеризацию тега от вызываемой функции?

Я открыт для любых предложений, использующих C ++ 11 variadic templates / Boost.Fusion или другое волшебство, которое упрощает мой текущий код (теперь я должен поддерживать 3 вместо 2 вспомогательных функций для каждой функции, которая использует эту конкретную диспетчеризацию, и с более сложная диспетчеризация, количество вспомогательных функций растет еще быстрее).

2

Решение

Чтобы выбрать одну из перегруженных функций, по крайней мере, вы должны указать компилятору типы аргументов целевой функции. Таким образом, мы можем добавить их в качестве аргументов типа класса шаблона mixed_dispatch

template < typename Tag, typename... Args >
class mixed_dispatch {
std::function<void(Tag,Args...)> invoke;

public:
// for overloaded functions
mixed_dispatch( void(&f)(Tag,Args...) ) : invoke( f ) { }

// for function objects
template < typename F >
mixed_dispatch( F&& f ) : invoke( std::forward<F>(f) ) { }

void operator()( Args... args ) const {
invoke( Tag(), args... );
}
};

Сейчас mixed_dispatch становится оберткой, которая поможет вам пройти Tag объекты к целевой функции. Как видите, нам нужно изменить сигнатуру целевой функции (немного работает).

void fun_impl(A1, bool) { std::cout << "A1\n"; }

В коде клиента, как fun:

template< typename T >
void fun( bool b, T )
{
using dispatcher = mixed_dispatch<T,bool>;
dispatcher d = fun_impl;
d( b );
}
1

Другие решения

Это отвечает на любые ваши вопросы?

// traits types
struct A1 {}; struct B1 {};
struct A2 {}; struct B2 {};

template<class T1, class T2>
struct TypeSelector
{
typedef T1 TTrue;
typedef T2 TFalse;
};

typedef TypeSelector<A1, B1> C1;
typedef TypeSelector<A2, B2> C2;

// helpers
void fun_impl(bool, A1) { std::cout << "A1\n"; }
void fun_impl(bool, B1) { std::cout << "B1\n"; }
void fun_impl(bool, A2) { std::cout << "A2\n"; }
void fun_impl(bool, B2) { std::cout << "B2\n"; }

template<class TSel>
void fun_impl(bool b, TSel) { if(b) fun_impl(b, typename TSel::TTrue()); else fun_impl(b, typename TSel::TFalse()); }

template<typename T>
void fun(bool b, T t)
{
// T = A, B, or C
fun_impl(b, t);
}

int main()
{
fun(true,  A1()); // "A1"fun(false, A1()); // "A1"fun(true,  B1()); // "B1"fun(false, B1()); // "B1"fun(true,  C1()); // "A1"fun(false, C1()); // "B1"fun(true,  C2()); // "A2"fun(false, C2()); // "B2"}

Или вы хотите упростить код в другом «измерении»?

0