【问题标题】:How to check if a class has specific function to avoid compile time issues?如何检查一个类是否具有特定功能以避免编译时问题?
【发布时间】:2020-12-25 17:32:25
【问题描述】:

我有两个 A 类和 B 类,有一个共同的函数对它们进行一些操作,只是略有不同。

我尝试使用 std::is_same,但看起来它不会阻止编译时问题。

class A {
public: 
    void aSpecificFunctionToA() {
    }
};

class B {
};


template<typename T>
void someFunction(T obj) {
    if(std::is_same<T, A>::value)
    {
        obj.aSpecificFunctionToA();
    }
}

如何解决这种情况?

【问题讨论】:

  • 你需要一个constexpr if
  • 也就是说,这通常是糟糕的设计。考虑将函数重载用于特定类型的东西。
  • @Someprogrammerdude 你能明确说明为什么这是一个糟糕的设计吗?因为它不是 API 的一部分,它可能会让用户感到惊讶。
  • 我使用的函数代码很长,变化仅针对 1 个特定函数。我想再次编写整个代码将是一个糟糕的设计,因为代码将是多余的。如果我错了,请纠正我。
  • @MartinMorterol 对类型的显式选择(如问题中所示)可能很快变得棘手,难以阅读和理解,因此也难以维护。使用语言本身的类型选择(重载)使代码更清晰、更干净、更易于维护。

标签: c++ c++11 templates compiler-errors


【解决方案1】:

如果你可以使用c++17,那么你可以使用if constexpr来有条件地编译满足某些约束的代码。

template<typename T>
void someFunction(T obj) {
    if constexpr (std::is_same<T, A>::value)
    {
        obj.aSpecificFunctionToA();
    }
    // ... code for all Ts
}

c++17之前,可以对A使用重载,把所有Ts通用的代码放到单独的函数中:

template<typename T>
void common_code(T obj) {
  // ... code for all Ts
}

template<typename T>
void someFunction(T obj) {
  common_code(obj);
}

void someFunction(A obj) {
  obj.aSpecificFunctionToA();
  common_code(obj);
}

【讨论】:

    【解决方案2】:

    如果你有不止一个类有aSpecificFunctionToA(好吧,在这种情况下这个名字不好选择)你可以使用 SFINAE。

    完整的 C++11:

    #include <vector>
    #include <functional>
    #include <iostream>
    #include <memory>
    #include <type_traits>
    
    namespace detail_traits
    {
    template <class...>
    struct Args
    {
    };
    
    template <class... T>
    using void_t = void;
    
    template <class T, class args, class = void>
    struct has_aSpecificFunctionToA : std::false_type
    {
    };
    template <class T, class... args>
    struct has_aSpecificFunctionToA<
        T,
        Args<args...>,
        void_t<decltype(std::declval<T>().aSpecificFunctionToA(std::declval<args>()...))>> : std::true_type
    {
    };
    
    } // namespace detail_traits
    template <class T, class... Args>
    using has_aSpecificFunctionToA = typename detail_traits::has_aSpecificFunctionToA<T, detail_traits::Args<Args...>>;
    
    
    class A
    {
      public:
        void aSpecificFunctionToA() {
        std::cout << "aSpecificFunctionToA" << std::endl;
        }
    };
    
    class B
    {
    };
    
    template <typename T>
    typename std::enable_if<has_aSpecificFunctionToA<T>::value>::type someFunction(T obj)
    {
            obj.aSpecificFunctionToA();
    }
    
    template <typename T>
    typename std::enable_if<!has_aSpecificFunctionToA<T>::value>::type someFunction(T )
    {
            std::cout << "some code for class without aSpecificFunctionToA" << std::endl;
    }
    
    int main()
    {
        std::cout << has_aSpecificFunctionToA<A>::value << std::endl;
        std::cout << has_aSpecificFunctionToA<B>::value << std::endl;
    
        someFunction(A{});
        someFunction(B{});
    }
    

    【讨论】:

      【解决方案3】:

      我更喜欢简单的老式解决方案:

      #define LOG std::cout << __PRETTY_FUNCTION__ << '\n'
      
      class A {
      public: 
          void aSpecificFunctionToA() {
              LOG;
          }
      };
      
      class B {
      };
      
      
      template<typename T>
      void someFunction(T obj) {
          LOG;
      }
      
      void someFunction(A obj) {
          LOG;
          obj.aSpecificFunctionToA();
      }
      

      https://godbolt.org/z/brPGr6

      【讨论】:

        【解决方案4】:

        此代码阻止编译器基于 const bool 表达式构建特定的 if 块。

        const bool flag = std::is_same<T, A>::value;
        #if(flag)
        {
            obj.aSpecificFunctionToA();
        }
        #endif
        

        【讨论】:

        • 预处理器指令(如#if)在代码实际编译之前处理。这意味着预处理器对变量一无所知,尤其是它们的值(即使它们是编译时常量)。
        猜你喜欢
        • 1970-01-01
        • 2016-04-05
        • 2012-03-13
        • 1970-01-01
        • 2017-11-06
        • 2023-02-16
        • 2012-02-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多