参数类型为空时禁用函数

时间:2015-04-25 09:55:50

标签: templates c++11 c++14 sfinae enable-if

我有一个模板类,如下所示:

template <typename T> constexpr bool is_value_passable_v = is_trivially_copyable_v<T> && sizeof(T) <= sizeof(void*) && !is_polymorphic_v<T>;
template <typename B, typename T> using param_base_t = conditional_t<is_value_passable_v<B>, T, const T&>;

template <typename T> struct param_d
{
    using type = param_base_t<T, T>;
};

template <> struct param_d<void>
{
    using type = void;
};

template <typename T> using param_t = typename param_d<T>::type;

template <class TIn> class CClass
{
    public:
        static constexpr bool use_input_v = !is_same_v<typename TIn::input_t, void>;
        using input_t = conditional_t<use_input_v, param_t<typename TIn::input_t>, void>;

        enable_if_t<use_input_v> Input(input_t i);
};

此代码的目标是为不同的模板参数提供不同的Input函数。

  • input_t = int的模板参数应为void Input(int i)
  • input_t = std::vector的模板参数应为void Input(const std::vector& i)
  • input_t = void的模板参数应删除Input函数

使用clang进行编译

/usr/bin/../include/c++/v1/type_traits:225:78: error: no type named 'type' in 'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable this declaration
template <bool _Bp, class _Tp = void> using enable_if_t = typename enable_if<_Bp, _Tp>::type;
                                                                             ^~~

编辑1: 添加行

template <typename T> static constexpr bool use_input2_v = use_input_v;

并用

替换函数声明
template <typename T = void> enable_if_t<use_input2_v<T>> Input(input_t i)

clang抱怨no matching member function for call to 'Input'

note: candidate template ignored: substitution failure [with T = void]: non-type template argument is not a constant expression
template <typename T = void> enable_if_t<use_input2_v<T>> Input(input_t i);
                                         ~~~~~~~~~~~~     ^

编辑2: 忘了提一下,这个错误带有模板参数的所有三种变体。

编辑3: CClass的示例用例可能是

class CInput0
{
    using input_t = int;
};

class CInput1
{
    using input_t = std::vector<int>;
};

class CInput2
{
    using input_t = void;
};

CClass<CInput0> in0;
CClass<CInput1> in1;
CClass<CInput2> in2;

std::vector<int> i = {1, 2, 3};

in0.Input(3);
in1.Input(i);
//in2.Input() disabled

2 个答案:

答案 0 :(得分:1)

为了使SFINAE工作,它需要处理依赖类型,否则没有替换失败。这是一个例子:

    template <typename Self = CClass<TIn>>
    typename std::enable_if<Self::use_input_v>::type
      Input(typename Self::input_t) { }

当成员函数是模板时,编译器会根据模板参数是否有效来有条件地创建它。在您的原始示例中,由于整个类是模板,但方法不是,因此只要实例化类,编译器就会将其视为您的成员函数的错误。使用默认模板参数只是我们需要的技巧。我们想要测试的内容现在被认为是依赖的。

答案 1 :(得分:0)

如果要根据模板参数的属性启用函数,而不进行部分特化,可以使用以下模式:

#include <iostream>
#include <type_traits>
#include <vector>

std::ostream& operator<<(std::ostream& out, std::vector<int>& value);

template <class TIn> class CClass
{
    public:         
        template <class T =TIn, class PARAM=  std::enable_if_t<!(std::is_same<void,typename T::input_t>::value) ,typename T::input_t > >
        void Input(PARAM i){
            std::cout << "Called Input with parameter: "<< i << std::endl;
        }
};

struct CInput0{ using input_t = int;};
struct CInput1{ using input_t = std::vector<int>;};
struct CInput2{ using input_t = void;};

CClass<CInput0> in0;
CClass<CInput1> in1;
CClass<CInput2> in2;

std::vector<int> i = {1, 2, 3};
std::ostream& operator<<(std::ostream& out, std::vector<int>& value) {
    for (auto& e:value) {
        out << e;
    } 
    out << std::endl;
    return out;
}

int main() {

    in0.Input(3);
    in1.Input(i);
    //in2.Input() disabled
}

这是您的示例的简化版本,您应该能够适应它。