2014-02-27 208 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; 
    } 
};