C++ 模板专业化:更改operator() 的返回类型?

use*_*231 3 c++ templates return-type template-specialization c++14

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

#include <vector>

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

这是有效的,除了 的情况return_T = void,因为 avector<void>是不可能的。所以我需要以A<void, arg_T>::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
{ }
Run Code Online (Sandbox Code Playgroud)

但编译器不喜欢它。

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
                                                        ^
Run Code Online (Sandbox Code Playgroud)

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

Cor*_*lks 5

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);
};
Run Code Online (Sandbox Code Playgroud)

这样你就不必专门化A,如果它很大的话会很方便,A并且专门化它会比仅仅专门化一个小的特征类更复杂。

  • 如果唯一的特殊情况是“void”,那么“std::conditional”就可以正常工作,无需引入单独的特征类。 (2认同)

Pio*_*cki 5

#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 {};
    }
};
Run Code Online (Sandbox Code Playgroud)

测试:

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>{}, "!");    
}
Run Code Online (Sandbox Code Playgroud)

演示版