2012-02-01 78 views
1

我想創建一個回調註冊類tat允許註冊對不同類型的字符串標識符的回調。每個回調都有簽名void function(T val),其中T是不斷變化的類型。variadic模板和mixins的歧義錯誤

我創建了以下基本註冊器類,它將字符串映射到函數。

#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操作爲:

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轉換爲基類類型?

回答

0

我有一個解決方案。所有需要的都是額外的間接水平。在派生類中我補充說,分派到正確的基礎模板的功能,如下所示:

template< typename... Types > 
class ConfigCallbackRegistrar : public BasicConfigCallbackRegistrar<Types>... 
{ 
    typedef ConfigCallbackRegistrar<Types...> type; 
public: 
    /// @brief constructor 
    ConfigCallbackRegistrar() : BasicConfigCallbackRegistrar<Types>()... 
    {} 

    template<typename T> 
    type& Register(string nodePath, 
      typename BasicConfigCallbackRegistrar<T>::signature_type callback) 
    { 
     BasicConfigCallbackRegistrar<T>::RegisterCallback(std::move(nodePath), 
       std::move(callback)); 
     return *this; 
    } 
}; 

調用代碼變爲:

int main() 
{ 
    CallbackRegistrar registrar{}; 

    registrar.Register<uint32_t>("SomeNode", UintFtor()); 
    registrar.Register<string>("SomeNode", StringFtor()); 

    return 0; 
}