可变模板和混合的歧义错误

Ambiguity errors with variadic templates and mixins

本文关键字:歧义 错误 混合      更新时间:2023-10-16

我正在尝试创建一个回调注册类tat,它允许根据不同类型的字符串标识符注册回调。每个回调都具有签名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]

对采用类型为value_type的参数的MakeCallback的调用也会产生相同的模糊性错误。

如果不将registrar显式转换为基类类型,如何解决此问题?

我有一个解决方案。所需要的只是一个额外级别的间接性。在Derived类中,我添加了一个模板函数,它将分派到正确的基,如下所示:

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;
}