基于模板元组的C++的C++实现方法

基于模板元组的C++的C++实现方法,c++,tuples,enable-if,C++,Tuples,Enable If,我试图在模板类中有选择地启用一个方法,但前提是tuple模板参数具有一定的arity。我一直在尝试各种组合,但到目前为止,还没有找到一种方法来编译下面的代码 本质上,当我用一个只有两个元素的元组实例化类foo时,我希望启用第一个void print方法,而当我用一个有三个元素的元组实例化foo时,我希望启用第二个void print方法 注意:这只是一个从我试图解决的更复杂问题中提炼出来的抽象示例。此外,我还可以使用基于两个特定元组的部分模板专门化来完成一些工作。然而,我真的很想了解enable

我试图在模板类中有选择地启用一个方法,但前提是tuple模板参数具有一定的arity。我一直在尝试各种组合,但到目前为止,还没有找到一种方法来编译下面的代码

本质上,当我用一个只有两个元素的元组实例化类foo时,我希望启用第一个void print方法,而当我用一个有三个元素的元组实例化foo时,我希望启用第二个void print方法

注意:这只是一个从我试图解决的更复杂问题中提炼出来的抽象示例。此外,我还可以使用基于两个特定元组的部分模板专门化来完成一些工作。然而,我真的很想了解enable_,如果我希望它能让我的代码更简单的话

多谢各位

// g++ -std=c++14 a.cc

#include <tuple>
#include <type_traits>
#include <iostream>

using namespace std;

template <class Tuple>
class foo {
public:
  Tuple t;  
 
  foo(Tuple ta) : t(ta) {
    cout<<"constructor\n";
  }  

  //How do I enable this print ONLY if arity of input tuple is 2  ???
  
  typename std::enable_if< std::tuple_size<Tuple>::value == 2, void >::type
  print(){
    cout<<get<0>(t)<<":"<<get<1>(t)<<"\n";
  }  

  // enable ONLY if arity 3 ???
  typename std::enable_if< std::tuple_size<Tuple>::value == 3, void >::type
  print(){
    cout<<get<0>(t)<<":"<<get<1>(t)<<"::"<<get<1>(t)<<"\n";
  }
};

int main(int argc, char**argv) {  
  typedef tuple<int, double>        t2_type;
  typedef tuple<int, double, float> t3_type;  

  t2_type t2(1,2.0);
  t3_type t3(100,100.0,2.3);  

  foo<t2_type> f2(t2);
  foo<t3_type> f3(t3);  

  f2.print();
  f3.print();
}
解决方案1源自以下答案:

#include <tuple>                                                                                                                                                                                                                                                                                                        
#include <type_traits>                                                                                                                                                                                                                                                                                                  
#include <iostream>                                                                                                                                                                                                                                                                                                     

using namespace std;                                                                                                                                                                                                                                                                                                    

template <class Tuple>                                                                                                                                                                                                                                                                                                  
class foo {                                                                                                                                                                                                                                                                                                             
public:
  Tuple t;

  foo(Tuple ta) : t(ta) {                                                                                                                                                                                                                                                                                               
    cout<<"constructor\n";                                                                                                                                                                                                                                                                                              
  }

  template <typename T = Tuple>
  typename std::enable_if< std::tuple_size<T>::value == 2, void >::type
  print(){
    cout<<get<0>(t)<<":"<<get<1>(t)<<"\n";
  }

  // enable ONLY if arity 3 ???                                                                                                                                                                                                                                                                                         
  template <typename T = Tuple>
  typename std::enable_if< std::tuple_size<T>::value == 3, void >::type
  print(){
    cout<<get<0>(t)<<":"<<get<1>(t)<<"::"<<get<1>(t)<<"\n";
  }

};

int main(int argc, char**argv) {
  typedef tuple<int, double>        t2_type;
  typedef tuple<int, double, float> t3_type;

  t2_type t2(1,2.0);
  t3_type t3(100,100.0,2.3);

  foo<t2_type> f2(t2);
  foo<t3_type> f3(t3);

  f2.print();
  f3.print();
}

enable_if不能基于类级模板参数。SFINAE必须在函数实例化时进行推导才能工作。将模板参数添加到打印应该可以做到这一点。对于size 2打印功能,如下所示

template<typename TupleParam>
typename std::enable_if< std::is_same<Tuple, TupleParam>::value && 
                         std::tuple_size<TupleParam>::value == 2, void >::type
print(){
    cout<<get<0>(t)<<":"<<get<1>(t)<<"\n";
} 

enable_if不能基于类级模板参数。SFINAE必须在函数实例化时进行推导才能工作。将模板参数添加到打印应该可以做到这一点。对于size 2打印功能,如下所示

template<typename TupleParam>
typename std::enable_if< std::is_same<Tuple, TupleParam>::value && 
                         std::tuple_size<TupleParam>::value == 2, void >::type
print(){
    cout<<get<0>(t)<<":"<<get<1>(t)<<"\n";
} 
您需要使打印成为一个模板,以便使用enable_if。为此,您只需使用类模板参数即可:

template <typename T = Tuple>
    typename std::enable_if< std::tuple_size<T>::value == 2, void >::type
print() {
    cout<<get<0>(t)<<":"<<get<1>(t)<<"\n";
}  

template <typename T = Tuple>
    typename std::enable_if< std::tuple_size<T>::value == 3, void >::type
print() {
    cout<<get<0>(t)<<":"<<get<1>(t)<<"::"<<get<1>(t)<<"\n";
}
这里有一个。

您需要将“打印”设置为模板,以便在必要时使用“启用”。为此,您只需使用类模板参数即可:

template <typename T = Tuple>
    typename std::enable_if< std::tuple_size<T>::value == 2, void >::type
print() {
    cout<<get<0>(t)<<":"<<get<1>(t)<<"\n";
}  

template <typename T = Tuple>
    typename std::enable_if< std::tuple_size<T>::value == 3, void >::type
print() {
    cout<<get<0>(t)<<":"<<get<1>(t)<<"::"<<get<1>(t)<<"\n";
}

这里有一个.

没有模板参数的默认值,用户必须清楚地拼写出来,如f2.print;或者我遗漏了什么?这个解决方案对我的案例进行了轻微的修改:“template”typename std::enable_如果::type print{…}`没有模板参数的默认值,必须明确地拼写出来,如f2.print;或者我遗漏了什么?这个解决方案对我的案例进行了轻微的修改:“template”typename std::enable_如果::type print{…}这是否回答了您的问题?这回答了你的问题吗?作为答案的一部分,我不知道这是否值得一提,但我至少要留下一条评论:从C++20开始,我们可以使用requires子句有条件地省略类模板的给定非模板重载成员函数的实例化,只基于类模板的模板参数上的条件。这意味着它将允许我们将打印重载保留为非模板函数。然而,还有w.r.t.如何保证省略违反ODR的重载实例化。是在对已提供显式实例化定义的类模板的Comstrated成员执行派生显式实例化时遵守约束:这种解释将使对类模板的非模板成员使用requires子句更有用我不知道它是否值得一提答案的一部分,但我至少要留下一条评论:从C++20开始,我们可以使用requires子句有条件地省略类模板的给定非模板重载成员函数的实例化,这完全基于类模板的模板参数上的条件。这意味着它将允许我们将打印重载保留为非模板函数。然而,还有w.r.t.如何保证省略违反ODR的重载实例化。是在对已提供显式实例化定义的类模板的组件成员执行派生显式实例化时遵守约束:这种解释将使对类模板的非模板成员使用requires子句更加有用