【问题标题】:C++ template specialization: change return type of operator()?C ++模板专业化:更改运算符()的返回类型?
【发布时间】:2015-11-02 02:05:57
【问题描述】:

在下面的类中,我定义了一个operator(),返回一个return_T的向量:

#include <vector>

template <typename return_T, typename ... arg_T>
class A
{
public:
    std::vector<return_T> operator()(arg_T... args);
};

这有效,除了return_T = void 的情况,因为vector&lt;void&gt; 是不可能的。所以我需要以某种方式定义A&lt;void, arg_T&gt;::operator() 的专业化。我正在试验以下代码:

#include <vector>

template <typename return_T, typename ... arg_T>
class A
{
public:
    auto operator()(arg_T... args);
};

template<typename return_T, typename... arg_T>
auto A<return_T, arg_T...>::operator()(arg_T... args) -> typename std::enable_if<!std::is_void<return_T>::value, std::vector<return_T>>::type
{ }

template<typename return_T, typename... arg_T>
auto A<void, arg_T...>::operator()(arg_T... args) -> void
{ }

但是编译器不喜欢它。

error : prototype for 'typename std::enable_if<(! std::is_void<_Tp>::value), std::vector<_Tp> >::type A<return_T, arg_T>::operator()(arg_T ...)' does not match any in class 'A<return_T, arg_T>'
   auto A<return_T, arg_T...>::operator()(arg_T... args) -> typename std::enable_if<!std::is_void<return_T>::value, std::vector<return_T>>::type

error : candidate is: auto A<return_T, arg_T>::operator()(arg_T ...)
       auto operator()(arg_T... args);
            ^

error : invalid use of incomplete type 'class A<void, arg_T ...>'
   auto A<void, arg_T...>::operator()(arg_T... args) -> void
                                                        ^

当然,我可以很容易地用void operator() 编写第二个类,但我很好奇它是否也可以用一个类来完成。所以我的问题是:这可能吗?

【问题讨论】:

    标签: c++ templates c++14 template-specialization return-type


    【解决方案1】:
    #include <type_traits>
    #include <utility>
    #include <vector>
    
    template <typename return_T, typename... arg_T>
    class A
    {
    public:
        auto operator()(arg_T... args)
        {
            return invoke(std::is_void<return_T>{}, std::forward<arg_T>(args)...);
        }
    
    private:
        void invoke(std::true_type, arg_T&&... args)
        {
        }
    
        std::vector<return_T> invoke(std::false_type, arg_T&&... args)
        {
            return {};
        }
    };
    

    测试:

    int main()
    {
        A<int, char, short> a;    
        static_assert(std::is_same<decltype(a('x', 5)), std::vector<int>>{}, "!");
    
        A<void, char, short> b;
        static_assert(std::is_same<decltype(b('x', 5)), void>{}, "!");    
    }
    

    DEMO

    【讨论】:

      【解决方案2】:

      您可以创建一个您专门化的“特征”类,而不是专门化 A

      template <typename return_T>
      struct Traits {
          using ReturnType = std::vector<return_T>;
      };
      
      template <>
      struct Traits<void> {
          using ReturnType = void;
      }
      
      template <typename return_T, typename ... arg_T>
      class A
      {
      public:
      
          typename Traits<return_T>::ReturnType operator()(arg_T... args);
      };
      

      这样您就不必专门化 A,如果 A 很大,那么专门化它会比只专门化一个小的特征类更复杂。

      【讨论】:

      • 我想出了相同的解决方案(但你更快+1)。但是我注意到很难通过有用的实现来正确地获得主体 operator()
      • @BryanChen:确实,函数的实际主体可能更复杂。但由于 OP 在他们的身体里没有任何东西,我让它尽可能简单。
      • 如果唯一的特殊情况是void,那么std::conditional 就可以正常工作,无需引入单独的特征类。
      • 我正在尝试这个,但仍然无法专门化实际功能......并且使用带有if (typeid(T) == typeid(void)) 的单个函数也不会编译。 :(
      • @Cornstalks 这个答案没什么意义,你怎么想象写这个函数的主体?
      猜你喜欢
      • 1970-01-01
      • 2020-07-18
      • 2016-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多