c++ - 仅对定义了功能的类型在功能模板内执行功能

标签 c++ c++11 templates c++14 metaprogramming

我有一个函数模板,它接受许多不同的类型。在这些类型中,只有一种具有getInt()函数。因此,我希望代码仅针对该类型运行函数。请提出解决方案。谢谢

#include <type_traits>
#include <typeinfo>

class X {
    public:
    int getInt(){
        return 9;
    }
};

class Y{

};

template<typename T>
void f(T& v){
    // error: 'class Y' has no member named 'getInt'
    // also tried std::is_same<T, X>::value 
    if(typeid(T).name() == typeid(X).name()){
        int i = v.getInt();// I want this to be called for X only
    }
}

int main(){
    Y y;
    f(y);
}

最佳答案

如果您希望能够为具有函数成员f的所有类型调用函数getInt,而不仅仅是X,则可以为f函数声明2个重载:

  • 用于具有getInt成员函数的类型,包括类X
  • 用于所有其他类型,包括Y类。

  • C++ 11/C++ 17解决方案

    考虑到这一点,您可以执行以下操作:

    #include <iostream>
    #include <type_traits>
    
    template <typename, typename = void>
    struct has_getInt : std::false_type {};
    
    template <typename T>
    struct has_getInt<T, std::void_t<decltype(((T*)nullptr)->getInt())>> : std::is_convertible<decltype(((T*)nullptr)->getInt()), int>
    {};
    
    class X {
    public:
        int getInt(){
            return 9;
        }
    };
    
    class Y {};
    
    template <typename T,
              typename std::enable_if<!has_getInt<T>::value, T>::type* = nullptr>
    void f(T& v) {
        // only for Y
        std::cout << "Y" << std::endl;
    }
    
    template <typename T,
              typename std::enable_if<has_getInt<T>::value, T>::type* = nullptr>
    void f(T& v){
        // only for X
        int i = v.getInt();
        std::cout << "X" << std::endl;
    }
    
    int main() {
        X x;
        f(x);
    
        Y y;
        f(y);
    }
    

    checkout live

    请注意 std::void_t 是C++ 17中引入的,但是如果您限于C++ 11,那么自己实现void_t真的很容易:

    template <typename...>
    using void_t = void;
    

    这是C++ 11版本live

    在C++ 20中我们有什么?

    C++ 20带来了很多美好的事物,其中之一就是concepts。以上对于C++ 11/C++ 14/C++ 17有效的事情在C++ 20中可以大大减少:

    #include <iostream>
    #include <concepts>
    
    template<typename T>
    concept HasGetInt = requires (T& v) { { v.getInt() } -> std::convertible_to<int>; };
    
    class X {
    public:
        int getInt(){
            return 9;
        }
    };
    
    class Y {};
    
    template <typename T>
    void f(T& v) {
        // only for Y
        std::cout << "Y" << std::endl;
    }
    
    template <HasGetInt T>
    void f(T& v){
        // only for X
        int i = v.getInt();
        std::cout << "X" << std::endl;
    }
    
    int main() {
        X x;
        f(x);
    
        Y y;
        f(y);
    }
    

    checkout live

    关于c++ - 仅对定义了功能的类型在功能模板内执行功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60112341/

    相关文章:

    templates - 如何使用 Go 将多个字符串解析为一个模板?

    c++ - 如何申报 SFINAE 类(class)?

    c++ - 比较文件统计时间

    c++ - QML 打开 GUI 窗口和控制台

    C++ 挑战 : Maximum unique reserved words in one logical line of code?

    C++ std::priority_queue 使用 lambda 表达式

    c++ - 右值 Hello World 缺少构造函数

    c++ - QT 可以与 Windows 原生集成吗?

    c++ - c++中令人困惑的事情

    WPF dataGrid(或ListView)通过绑定(bind)填充,不同的行模板