Я пытаюсь создать класс регистрации обратного вызова, позволяющий регистрировать обратные вызовы по строковому идентификатору для различных типов. Каждый обратный вызов имеет подпись void function( T val )
, где T
- это изменяющийся тип.
Я создал следующий базовый класс регистратора, который отображает строки в функции.
#include <string>
#include <map>
#include <functional>
#include <cstdint>
#include <iostream>
using namespace std;
template< typename ValueType >
class BasicConfigCallbackRegistrar
{
public:
typedef ValueType value_type;
typedef BasicConfigCallbackRegistrar< value_type > type;
typedef function< void( const value_type ) > signature_type;
typedef map< string, signature_type > callback_map_type;
/// @brief constructor
BasicConfigCallbackRegistrar() : callbackMap_()
{
}
/// @brief register a create callback
/// @param nodePath the path identifying the node in config database
/// @param callback the callback to register
type& RegisterCallback( string nodePath, signature_type callback )
{
callbackMap_.insert( make_pair( move(nodePath), callback ) );
return *this;
}
void MakeCallback( const string& nodePath, value_type val )
{
// no checking assumes item is in map,
// do not do this in production code
auto iter = callbackMap_.find( nodePath );
iter->second( val );
}
private:
callback_map_type callbackMap_; ///< the callback map
};
Затем я использую шаблоны переменных для создания производного класса для каждого из типов, которые я хочу поддерживать.
template< typename... Types >
class ConfigCallbackRegistrar : public BasicConfigCallbackRegistrar<Types>...
{
public:
/// @brief constructor
ConfigCallbackRegistrar() : BasicConfigCallbackRegistrar<Types>()...
{}
};
Затем этот код определяется как:
typedef ConfigCallbackRegistrar< uint32_t, string > CallbackRegistrar;
Когда я пытаюсь использовать этот класс следующим образом:
struct UintFtor
{
void operator()( uint32_t val )
{
cout << val << "\n";
}
};
struct StringFtor
{
void operator ()( string val )
{
cout << val << "\n";
}
};
int main()
{
CallbackRegistrar registrar{};
registrar.RegisterCallback( "SomeNode", UintFtor() );
registrar.RegisterCallback( "SomeNode", StringFtor() );
return 0;
}
К сожалению, когда я пытаюсь скомпилировать это, я получаю следующие ошибки неоднозначности:
variadic-wrap.cpp: In function ‘int main()’:
variadic-wrap.cpp:87: error: request for member ‘RegisterCallback’ is ambiguous
variadic-wrap.cpp:27: error: candidates are: BasicConfigCallbackRegistrar<ValueType>& BasicConfigCallbackRegistrar<ValueType>::RegisterCallback(std::string, std::function<void(ValueType)>) [with ValueType = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]
variadic-wrap.cpp:27: error: BasicConfigCallbackRegistrar<ValueType>& BasicConfigCallbackRegistrar<ValueType>::RegisterCallback(std::string, std::function<void(ValueType)>) [with ValueType = unsigned int]
variadic-wrap.cpp:88: error: request for member ‘RegisterCallback’ is ambiguous
variadic-wrap.cpp:27: error: candidates are: BasicConfigCallbackRegistrar<ValueType>& BasicConfigCallbackRegistrar<ValueType>::RegisterCallback(std::string, std::function<void(ValueType)>) [with ValueType = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]
variadic-wrap.cpp:27: error: BasicConfigCallbackRegistrar<ValueType>& BasicConfigCallbackRegistrar<ValueType>::RegisterCallback(std::string, std::function<void(ValueType)>) [with ValueType = unsigned int]
Вызов MakeCallback
, который принимает параметр типа value_type
, также приводит к той же ошибке неоднозначности.
Как я могу решить эту проблему без явного приведения registrar
к типу базового класса?