2012-04-06 31 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

相關問題