2014-02-27 210 views
2

我想檢查一個模板類型並適當地調用一個函數。但是,這似乎並不奏效。我嘗試了is_same,C++ compile-time type checking,compile-time function for checking type equality和boost :: is_same。一切都給了我同樣的錯誤。以下是示例代碼。編譯時檢查模板類型C++

#include <iostream> 
#include <type_traits> 
using namespace std; 

class Numeric 
{ 
public : 
    bool isNumeric() 
    { 
    return true; 
    } 
}; 
class String 
{ 

}; 

template <class T> 
class Myclass 
{ 
    private: 
    T temp; 
    public: 
    void checkNumeric() 
    { 
     if(std::is_same<T,Numeric>::value) 
     { 
      cout << "is numeric = " << temp.isNumeric(); 
     } 
     else 
     { 
      cout << "is numeric = false" << endl; 
     } 
    } 

}; 

int main() 
{ 
    Myclass<Numeric> a; 
    a.checkNumeric(); 
    Myclass<String> b; 
    b.checkNumeric(); 
} 

編譯上述代碼時,出現以下錯誤。

make all 
Building file: ../src/TestCPP.cpp 
Invoking: GCC C++ Compiler 
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/TestCPP.d" -MT"src/TestCPP.d" -o "src/TestCPP.o" "../src/TestCPP.cpp" 
../src/TestCPP.cpp:36:36: error: no member named 'isNumeric' in 'String' 
        cout << "is numeric = " << temp.isNumeric(); 
               ~~~~^
../src/TestCPP.cpp:51:4: note: in instantiation of member function    'Myclass<String>::checkNumeric' requested here 
    b.checkNumeric(); 
    ^
1 error generated. 
make: *** [src/TestCPP.o] Error 1 

在這種情況下,我既沒有字符串也沒有數字類。它來自第三方庫。我只實現MyClass,它將被打包爲另一個庫。我期望使用MyClass的應用程序將傳遞給我一個屬於第三方類的String或Numeric。 MyClass是一種專門的矩陣操作,密集/稀疏矩陣是來自第三方庫的數字和字符串類。我想檢查使用我的庫和第三方庫的應用程序是否正在根據屬於第三方庫的類類型調用MyClass。

請讓我知道如何解決這個問題。

回答

9

不需要做任何事情;這可以使用普通模板專業化進行處理。

template <class T> 
class Myclass 
{ 
    private: 
    T temp; 

    public: 
    // called for general T 
    void checkNumeric() { 
     cout << "is numeric = false" << endl; 
    } 
}; 

// specialized version for T = Numeric 
template<> void Myclass<Numeric>::checkNumeric() { 
    cout << "is numeric = " << temp.isNumeric() << endl; 
} 
+0

我既沒有字符串或數字類。它來自第三方庫。我只實現MyClass,它將被打包爲另一個庫。使用MyClass的應用程序將傳遞給我一個屬於第三方類的String或Numeric。例如,String和Numeric類是來自第三方庫的密集和稀疏矩陣。我想檢查使用我的庫和第三方庫的應用程序是否正在根據屬於第三方庫的類類型調用MyClass。 –

+2

@RamakrishnanKannan:這個答案只改變了'Myclass' –

+1

只是要清楚,這可以使用SFINAE。關鍵是編譯器有兩個版本的'checkNumeric',如果其中一個產生了錯誤,那麼它將被默認地從考慮中刪除。 – Adam

2

MyClass<T>::checkNumeric()來電T::isNumeric()。你的String類沒有這樣的功能,所以MyClass<String>::checkNumeric()不能編譯。

選項:

  • 添加和落實String::isNumeric()
  • 你已經從std::is_same得到你的答案,那麼爲什麼要撥打isNumeric()呢?
+0

我既沒有字符串也沒有數字類。它來自第三方庫。我只實現MyClass,它將被打包爲另一個庫。使用MyClass的應用程序將傳遞給我一個屬於第三方類的String或Numeric。例如,String和Numeric類是來自第三方庫的密集和稀疏矩陣。我想檢查使用我的庫和第三方庫的應用程序是否正在根據屬於第三方庫的類類型調用MyClass。 –

+0

@RamakrishnanKannan這聽起來像我的第二點要處理你的情況。我不明白爲什麼只是「is_same」是不夠的。 – Adam

3

if else將強制編譯器實例化兩個控制流。由於有些情況下T不是Numeric類型(儘管代碼可能不會通過該路徑運行),這將導致編譯錯誤。你需要的是一個編譯時的控制流,事中的if_then_else

template<int condition, int true_val, int false_val> 
struct if_then_else { 
    enum { val = true_val }; 
}; 

template<int true_val, int false_val> 
struct if_then_else<false, true_val, false_val> { 
    enum { val = false_val }; 
}; 

線然後if_then_else< std::is_same<T, Numeric>::value, 1, 0>::value將給予1(真)爲Numeric類型和0(假)與非數字的人,而不需要被無效實例化非數字。

+0

你如何爲模板參數編譯時間控制流? – Adam

+0

@Adam:使用函數重載。你可以使用'enable_if'來給出兩種不同的類型並調用兩個不同的函數,或者你可以專注於一個布爾型的非類型模板參數。或者你可以專注於開始的類型。 –

+0

@Adam假設你有C++ 11,有'std :: conditional','std :: enable_if'等。我提供了一個手工製作的例子。通常,控制流程是用編譯時遞歸來模擬的(參見例如循環展開),但在這種簡單的情況下並不需要這樣。 –

3

您需要在編譯期間選擇啓用/禁用功能,而不是在運行期間。我建議做類似的東西(code on ideone.com):

#include <iostream> 
#include <type_traits> 

class Numeric { 
public: 
    bool isNumeric() { 
    return true; 
    } 
}; 

class String { 
}; 

template<class T> 
class Myclass { 
private: 
    T temp; 
public: 
    template<typename U = T, typename std::enable_if<std::is_same<U, Numeric>::value, std::size_t>::type = 0> 
    void checkNumeric() { 
    std::cout << "is numeric = " << temp.isNumeric() << std::endl; 
    } 

    template<typename U = T, typename std::enable_if<!std::is_same<U, Numeric>::value, std::size_t>::type = 0> 
    void checkNumeric() { 
    std::cout << "is numeric = false" << std::endl; 
    } 
}; 

int main() { 
Myclass<Numeric> a; 
a.checkNumeric(); 
Myclass<String> b; 
b.checkNumeric(); 
} 

程序輸出:

is numeric = 1 
is numeric = false 

希望這有助於。

0

有兩種方法可以解決這個問題。

  1. addNumeric()加到String。如果您有權修改String,這是最簡單的解決方案。
  2. 如果您無權修改String,則可以使用助手類來幫助完成此過程。

這裏是助手類。

template <typename T1> struct IsNumeric 
{ 
    static bool get(T1 const& temp) 
    { 
     return false; 
    } 
}; 

template <> struct IsNumeric<Numeric> 
{ 
    static bool get(Numeric const& temp) 
    { 
     return temp.isNumeric(); 
    } 
}; 

這是你的主類:

template <class T> 
class Myclass 
{ 
    private: 
    T temp; 

    public: 

    void checkNumeric() 
    { 
     std::cout << " is numeric = " << IsNumeric<T>::get(temp) << std::endl; 
    } 
};