【问题标题】:How do I resolve this <unresolved overloaded function type> error when using std::function?使用 std::function 时如何解决此 <未解决的重载函数类型> 错误?
【发布时间】:2012-04-06 01:48:14
【问题描述】:

在以下(工作)代码示例中,模板化的 register_enum() 函数用于迭代枚举并调用用户提供的回调以将枚举值转换为 c 字符串。所有枚举都在一个类中定义,枚举到字符串的转换是使用静态 to_cstring( enum ) 函数完成的。当一个类(如下面的着色器类)具有多个枚举和相应的重载 to_cstring(enum) 函数时,编译器无法确定传递给 register_enum() 的正确 to_cstring() 函数。我认为代码比我解释得更好......

#include <functional>
#include <iostream>

// Actual code uses Lua, but for simplification
// I'll hide it in this example.
typedef void lua_State;

class widget
{
    public:
        enum class TYPE
        {
            BEGIN = 0,
            WINDOW = BEGIN,
            BUTTON,
            SCROLL,
            PROGRESS,
            END
        };

        static const char *to_cstring( const TYPE value )
        {
            switch ( value )
            {
                case TYPE::WINDOW: return "window";
                case TYPE::BUTTON: return "button";
                case TYPE::SCROLL: return "scroll";
                case TYPE::PROGRESS: return "progress";
                default: break;
            }
            return nullptr;
        }
};

class shader
{
    public:
        enum class FUNC
        {
            BEGIN = 0,
            TRANSLATE = BEGIN,
            ROTATE,
            SCALE,
            COLOR,
            COORD,
            END
        };

        enum class WAVEFORM
        {
            BEGIN = 0,
            SINE = BEGIN,
            SQUARE,
            TRIANGLE,
            LINEAR,
            NOISE,
            END
        };

        static const char *to_cstring( const FUNC value )
        {
            switch ( value )
            {
                case FUNC::TRANSLATE: return "translate";
                case FUNC::ROTATE: return "rotate";
                case FUNC::SCALE: return "scale";
                case FUNC::COLOR: return "color";
                case FUNC::COORD: return "coord";
                default: break;
            }
            return nullptr;
        }

        static const char *to_cstring( const WAVEFORM value )
        {
            switch ( value )
            {
                case WAVEFORM::SINE: return "sine";
                case WAVEFORM::SQUARE: return "square";
                case WAVEFORM::TRIANGLE: return "triangle";
                case WAVEFORM::LINEAR: return "linear";
                case WAVEFORM::NOISE: return "noise";
                default: break;
            }
            return nullptr;
        }
};

// Increment an enum value.
// My compiler (g++ 4.6) doesn't support type_traits for enumerations, so
// here I just static_cast the enum value to int... Something to be fixed
// later...
template < class E >
E &enum_increment( E &value )
{
    return value = ( value == E::END ) ? E::BEGIN : E( static_cast<int>( value ) + 1 );
}

widget::TYPE &operator++( widget::TYPE &e )
{
    return enum_increment< widget::TYPE >( e );
}

shader::FUNC &operator++( shader::FUNC &e )
{
    return enum_increment< shader::FUNC >( e );
}

shader::WAVEFORM &operator++( shader::WAVEFORM &e )
{
    return enum_increment< shader::WAVEFORM >( e );
}


// Register the enumeration with Lua
template< class E >
void register_enum( lua_State *L, const char *table_name, std::function< const char*( E ) > to_cstring )
{
    (void)L; // Not used in this example.
    // Actual code creates a table in Lua and sets table[ to_cstring( i ) ] = i
    for ( auto i = E::BEGIN; i < E::END; ++i )
    {
        // For now, assume to_cstring can't return nullptr...
        const char *key = to_cstring( i );
        const int value = static_cast<int>(i);
        std::cout << table_name << "." << key << " = " << value << std::endl;
    }
}

int main( int argc, char **argv )
{
    (void)argc; (void)argv;

    lua_State *L = nullptr;

    // Only one to_cstring function in widget class so this works...
    register_enum< widget::TYPE >( L, "widgets", widget::to_cstring );

    // ... but these don't know which to_cstring to use.
    register_enum< shader::FUNC >( L, "functions", shader::to_cstring );
    //register_enum< shader::WAVEFORM >( L, "waveforms", shader::to_cstring );

    return 0;
}

编译器输出:

$ g++ -std=c++0x -Wall -Wextra -pedantic test.cpp -o test && ./test
test.cpp: In function ‘int main(int, char**)’:
test.cpp:140:69: error: no matching function for call to ‘register_enum(lua_State*&, const char [10], <unresolved overloaded function type>)’
test.cpp:140:69: note: candidate is:
test.cpp:117:7: note: template<class E> void register_enum(lua_State*, const char*, std::function<const char*(E)>)

如何将正确的 to_cstring 函数传递给 register_enum()?我意识到我可以重命名各个 to_cstring() 函数,但如果可能的话,我想避免这种情况。可能我的设计有异味,你可以推荐一个更好的方法。

我的问题与Calling overloaded function using templates (unresolved overloaded function type compiler error)How to get the address of an overloaded member function? 类似,但到目前为止我无法将该信息应用于我的具体问题。

【问题讨论】:

    标签: c++ c++11


    【解决方案1】:

    该错误告诉您有两个潜在的重载可以使用,编译器无法为您做出决定。另一方面,您可以通过使用强制转换来确定使用哪个:

    typedef const char *(*func_ptr)( shader::FUNC );
    register_enum< shader::FUNC >( L, "functions", (func_ptr)shader::to_cstring );
    

    或者没有 typedef(在一个更难阅读的单行中):

    register_enum< shader::FUNC >( L, "functions", 
                 (const char *(*)( shader::FUNC ))shader::to_cstring );
    

    *请注意,在函数签名中,顶级const 被删除。

    下一个问题是为什么编译器自己没有找到合适的重载?问题在于,在对register_enum 的调用中,您传递了枚举的类型,这将确定std::function 的类型为std::function&lt; const char* ( shader::FUNC ) &gt;,但std::function 有一个模板化的构造函数,并且在尝试推断之前构造函数的参数类型,编译器必须知道你想使用哪个重载。

    【讨论】:

      【解决方案2】:

      我想说,在这种情况下,如果编译器无法在两个重载之间做出决定,您应该重命名其中一个!这将防止函数的进一步模棱两可的使用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-19
        • 2013-02-20
        • 1970-01-01
        • 1970-01-01
        • 2023-04-08
        • 2019-10-11
        • 2020-06-23
        • 1970-01-01
        相关资源
        最近更新 更多