简体   繁体   English

在类模板方法中使用 enable_if 检查两个函数参数是否都是 std::array 或都是 std::vector

[英]Using enable_if, in class template method, to check if two function arguments arguments are both std::array or both std::vector

I am not a professional coder and I apologise if my question seams naive or malformed.我不是专业的编码员,如果我的问题显得幼稚或格式错误,我深表歉意。

I am trying to have a class member function take std::array or std::vector in the arguments.我试图让一个类成员函数在参数中使用std::arraystd::vector Specifically I am passing two arguments that should either both be std::array or both be std::vector .具体来说,我传递了两个参数,它们要么都是std::array要么都是std::vector

BEFORE trying to make the above work, a minimum set up of what I had was working only with std::vector arguments.在尝试进行上述工作之前,我所拥有的最小设置仅适用于std::vector参数。 a minimum set up is as follows, where v and p are the ones I desire to have passed as vectors or arrays:最小设置如下,其中vp是我希望作为向量或数组传递的那些:

// original version

class my_class_A{
// stuf
};

class my_class_B{
// other stuf
};

class I_am_a_class_of_methods{
public:
  inline void my_method(const std::vector<my_class_A> &v,
                        const std::vector<std::array<uint64_t,2> > &p,
                        const my_class_B &x,
                        my_class_B &y){
    // `v` and `p` are used to modify `x` and store the result in `y`
    return;
  }; 
};

I understand I could do what I want with function overloading, however, I decided I wanted to achieve the desired result with templates and std::enable_if , to force me to learn a bit more about them.我知道我可以用函数重载做我想做的事,但是,我决定用templatesstd::enable_if来达到预期的结果,迫使我更多地了解它们。 Well I did learn a lot I didn't know... but not enough it seams.好吧,我确实学到了很多我不知道的东西……但还不够。 I have basically tried setting up a trait is_both_array_or_vector , and std::enable_if will check to see if the template call matches the trait.我基本上尝试过设置特征is_both_array_or_vector ,并且std::enable_if将检查模板调用是否与特征匹配。 The final thing I tried is the following, which did compile, but it will only work for std::vector :我尝试的最后一件事是以下内容,它确实可以编译,但它仅适用于std::vector

// current version

class my_class_A{
// stuf
};

class my_class_B{
// other stuf
};

// set up a type trait to check if both are vector or both are array
template <typename T1, typename T2>                                                                                                                                                                         
struct is_both_array_or_vector{                                                                                                                                                                             
  enum { value = false };                                                                                                                                                                                   
};                                                                                                                                                                                                          

template <typename T1, typename T2, typename A1, typename A2 >                                                                                                                                              
struct is_both_array_or_vector<std::vector<T1, A1>, std::vector<T2, A2> > {                                                                                                                                 
  enum { value = true };                                                                                                                                                                                    
};                                                                                                                                                                                                          

template <typename T1, typename T2, size_t D>                                                                                                                                                               
struct is_both_array_or_vector<std::array<T1, D>, std::array<T2, D> > {                                                                                                                                     
  enum { value = true };                                                                                                                                                                                    
}; 

// conditionally compile with enable_if
class I_am_a_class_of_methods{
public:
  template<template<typename,typename> U, template<typename,typename> S,
           typename Au, typename As> 
  typename std::enable_if<is_both_array_or_vector<U<my_class_A, Au>, S<std::array<uint64_t,2>,As> >::value >::type
  my_method(const U<my_class_A, Au> &v,
            const S<std::array<uint64_t,2>, As> &p,
            const my_class_B &x,
            my_class_B &y){
    // `v` and `p` are used to modify `x` and store the result in `y`
    return;
  }; 
};

When I compile with std::vector call from main everything works fine.当我使用来自 main 的std::vector调用编译时,一切正常。 This (of course) doesn't compile with std::array call (compiler of course complains).这(当然)不能用std::array调用编译(编译器当然会抱怨)。

If only I could make template arguments As and Au be able to be interpreted as size_t , then the template would find a match with an std::array call.如果我能让模板参数AsAu能够被解释为size_t ,那么模板将找到与std::array调用的匹配项。 This doesn't seam possible however, since I can have either typename or size_t , not both as far as I know.然而,这不可能接缝,因为我可以拥有typenamesize_t ,据我所知,不能同时拥有。 Thus my question is, how would I get enable_if to work in this circumstance?因此我的问题是,在这种情况下我如何让 enable_if 工作?

Update: As Javier said, you can keep a private function template that will handle the general case, and overload two methods for the types you want and pass them to that template.更新:正如 Javier 所说,您可以保留一个私有函数模板来处理一般情况,并为您想要的类型重载两个方法并将它们传递给该模板。

class I_am_a_class_of_methods {
private:
  template <typename C1, typename C2>
  void my_method_priv(const C1& v, const C2& p, const my_class_B& x, my_class_B& y) {
    // ...
  }

 public:
  void my_method(const std::vector<my_class_A>& v,
                 const std::vector<array<uint64_t, 2>>& p,
                 const my_class_B& x,
                 my_class_B& y)
  { my_method_priv(v, p, x, y); }

  template <size_t N1, size_t N2>
  void my_method(const std::array<my_class_A, N1>& v,
                 const std::array<std::array<uint64_t, 2>, N2>& p,
                 const my_class_B& x,
                 my_class_B& y)
  { my_method_priv(v, p, x, y); }
};

I would highly recommend using function overloads as the optimal solution here.我强烈建议在这里使用函数重载作为最佳解决方案。 However, you said you wanted to experiment and learn.然而,你说你想尝试和学习。 Since that is the case, please allow me to demonstrate one approach in that vein.既然如此,请允许我展示一种与此类似的方法。

Note that this is a bit complicated because you want explicit template arguments, but there is not that much more metaprogramming involved in the detection, and it at least gives you an idea of how to approach something like this when it is wise to do so - but in this case just use function overloads.请注意,这有点复杂,因为您需要显式模板参数,但检测中并没有涉及更多的元编程,它至少让您了解如何在明智的情况下处理这样的事情 -但在这种情况下,只需使用函数重载。

class I_am_a_class_of_methods
{
    template <typename FirstT, typename SecondT>
    struct Enable { };
    template <typename A1, typename A2>
    struct Enable<std::vector<my_class_A, A1>,
                  std::vector<std::array<uint64_t,2>, A2>>
    {
        using type = void;
    };
    template <std::size_t N1, std::size_t N2>
    struct Enable<std::array<my_class_A, N1>,
                  std::array<std::array<uint64_t,2>, N2>>
    {
        using type = void;
    };

public:
    template <typename T1, typename T2>
    typename Enable<std::decay_t<T1>, std::decay_t<T2>>::type
    my_method(T1 const &v, T2 const &p, my_class_B const &x, my_class_B &y)
    {
        // whatever
    }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM