【问题标题】:Disable Function when parameter type is void参数类型为空时禁用函数
【发布时间】:2015-07-04 00:20:22
【问题描述】:

我有一个看起来像这样的模板类:

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&amp; 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

【问题讨论】:

  • 你为什么不只使用static constexpr bool use_input_v = !is_same&lt;typename TIn::input_t, void&gt;;
  • 而不是 use_input2_v 版本? Afaik enable_if 只能禁用基于“直接”模板的功能。
  • template &lt;typename T&gt; constexpr bool is_value_passable_v = is_trivially_copyable_v&lt;T&gt; &amp;&amp; sizeof(T) &lt;= sizeof(void*) &amp;&amp; !is_polymorphic_v&lt;T&gt;; 这是什么?它既不是函数也不是类模板。
  • 对不起!这是一个 c++14 变量模板。忘记了相应的标签。
  • TIn::input_t 来自哪里?或者换个方式问:你是如何实例化CClass的?

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


【解决方案1】:

要使 SFINAE 工作,它需要使用依赖类型,否则不会出现替换失败。这是一个例子:

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

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

【讨论】:

    【解决方案2】:

    如果您想根据模板参数的属性启用功能,无需部分特化,您可以使用以下模式:

    #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
    }
    

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

    【讨论】:

      猜你喜欢
      • 2018-07-21
      • 2019-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-16
      • 2021-04-04
      相关资源
      最近更新 更多