2012-04-06 160 views
8

在以下(工作)代码示例中,使用模板化register_enum()函数遍历枚举并调用用户提供的回调函数以将枚举值转换为c字符串。所有的枚举都是在一个类中定义的,枚举到字符串的转换是通过一个静态的to_cstring(枚举)函数完成的。当一个类(如下面的着色器类)有多个枚举和相应的重载to_cstring(枚举)函数时,编译器无法决定哪个是传递给register_enum()的正确的to_cstring()函数。我觉得代码解释比我能更好...如何在使用std :: function时解决这个<未解析的重载函数类型>错误?

#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?但到目前为止,我无法将这些信息应用到我的特定问题。

回答

6

该错误告诉您有两个可能的重载可以使用,并且编译器无法为您做出决定。在另一方面,你可以决定使用强制使用哪一个:

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< const char* (shader::FUNC) >,但std::function具有模板构造函数,并且在尝试推断构造函数的参数类型之前,编译器必须知道你想使用哪个超载。

-1

我会说在这种情况下,如果编译器不能决定两个重载之间,你应该重命名其中的一个!这将防止功能的进一步模糊使用。

+0

为什么downvote?这是一个更简单的解决方案。 – xcski 2018-01-18 23:19:02

相关问题