简体   繁体   English

在C ++中,如何根据类中的参数返回不同的泛型类型?

[英]In C++, how to return different generic types depending on argument in a class?

I have this code: 我有以下代码:

template<class T1, class T2>
class Pair
{
private:
    T1 first;
    T2 second;

public:
    void SetFirst(T1 first)
    {
        this.first = first;
    }
    void SetSecond(T2 second)
    {
        this.second = second;
    }
    T1 GetFirst()
    {
        return first;
    }
    T2 GetSecond()
    {
        return second;
    }
};

How could I implement two single methods SetValue() and GetValue() , instead of the four I have, that decides depending on parameters which generic type that should be used? 如何实现两个单独的方法SetValue()GetValue() ,而不是我拥有的四个方法,这些方法根据参数决定应使用哪种泛型类型? For instance I'm thinking the GetValue() method could take an int parameter of either 1 or 2 and depending on the number, return either a variable of type T1 or T2 . 例如,我在考虑GetValue()方法可以采用1或2的int参数,并根据数字,返回T1T2类型的变量。 But I don't know the return type beforehand so is there anyway to solve this? 但是我事先不知道返回类型,所以有解决办法吗?

Not sure to understand what do you want and not exactly what you asked but... 不知道您想要什么,而不是确切地了解您的要求,但是...

I propose the use of a wrapper base class defined as follows 我建议使用定义如下的包装器基类

template <typename T>
class wrap
 {
   private:
      T  elem;

   public:
      void set (T const & t)
       { elem = t; }

      T get () const
       { return elem; }
 };

Now your class can be defined as 现在您的班级可以定义为

template <typename T1, typename T2>
struct Pair : wrap<T1>, wrap<T2>
 {
   template <typename T>
   void set (T const & t)
    { wrap<T>::set(t); }

   template <typename T>
   T get () const
    { return wrap<T>::get(); }
 };

or, if you can use C++11 and variadic templates and if you define a type traits getType to get the Nth type of a list, 或者,如果可以使用C ++ 11和可变参数模板,并且定义类型traits getType以获取列表的第N个类型,

template <std::size_t I, typename, typename ... Ts>
struct getType
 { using type = typename getType<I-1U, Ts...>::type; };

template <typename T, typename ... Ts>
struct getType<0U, T, Ts...>
 { using type = T; };

you can define Pair in a more flexible way as follows 您可以按以下更灵活的方式定义“ Pair

template <typename ... Ts>
struct Pair : wrap<Ts>...
 {
   template <typename T>
   void set (T const & t)
    { wrap<T>::set(t); }

   template <std::size_t N, typename T>
   void set (T const & t)
    { wrap<typename getType<N, Ts...>::type>::set(t); }

   template <typename T>
   T get () const
    { return wrap<T>::get(); }

   template <std::size_t N>
   typename getType<N, Ts...>::type get ()
    { return wrap<typename getType<N, Ts...>::type>::get(); }
 };

Now the argument of set() can select the correct base class and the correct base element 现在, set()的参数可以选择正确的基类和正确的基元素

   Pair<int, long>  p;

   p.set(0);  // set the int elem
   p.set(1L); // set the long elem

otherwise, via index, you can write 否则,通过索引,您可以编写

   p.set<0U>(3); // set the 1st (int) elem
   p.set<1U>(4); // set the 2nd (long) elem

Unfortunately, the get() doesn't receive an argument, so the type have to be explicited (via type or via index) 不幸的是, get()没有收到参数,因此必须明确类型(通过类型或通过索引)

   p.get<int>();  // get the int elem value
   p.get<long>(); // get the long elem value

   p.get<0U>(); // get the 1st (int) elem value
   p.get<1U>(); // get the 2nd (long) elem value 

Obviously, this didn't work when T1 is equal to T2 显然,这在T1等于T2时不起作用

The following is a (C++11) full working example 以下是(C ++ 11)完整的工作示例

#include <iostream>

template <std::size_t I, typename, typename ... Ts>
struct getType
 { using type = typename getType<I-1U, Ts...>::type; };

template <typename T, typename ... Ts>
struct getType<0U, T, Ts...>
 { using type = T; };

template <typename T>
class wrap
 {
   private:
      T  elem;

   public:
      void set (T const & t)
       { elem = t; }

      T get () const
       { return elem; }
 };

template <typename ... Ts>
struct Pair : wrap<Ts>...
 {
   template <typename T>
   void set (T const & t)
    { wrap<T>::set(t); }

   template <std::size_t N, typename T>
   void set (T const & t)
    { wrap<typename getType<N, Ts...>::type>::set(t); }

   template <typename T>
   T get () const
    { return wrap<T>::get(); }

   template <std::size_t N>
   typename getType<N, Ts...>::type get ()
    { return wrap<typename getType<N, Ts...>::type>::get(); }
 };

int main()
 {
   //Pair<int, int>  p;  compilation error
   Pair<int, long, long long>  p;

   p.set(0);
   p.set(1L);
   p.set(2LL);

   std::cout << p.get<int>() << std::endl;       // print 0
   std::cout << p.get<long>() << std::endl;      // print 1
   std::cout << p.get<long long>() << std::endl; // print 2

   p.set<0U>(3);
   p.set<1U>(4);
   p.set<2U>(5);

   std::cout << p.get<0U>() << std::endl; // print 3
   std::cout << p.get<1U>() << std::endl; // print 4
   std::cout << p.get<2U>() << std::endl; // print 5
 }

C++ is statically typed, so the argument given must be a template-argument instead a function-argument. C ++是静态类型的,因此给定的参数必须是模板参数而不是函数参数。

And while it will look like just one function each to the user, it's really two. 尽管对于用户来说,每个功能看起来就像一个功能,但实际上是两个功能。

template <int i = 1> auto GetValue() -> std::enable_if_t<i == 1, T1> { return first; }
template <int i = 2> auto GetValue() -> std::enable_if_t<i == 2, T2> { return second; }
template <int i = 1> auto SetValue(T1 x) -> std::enable_if_t<i == 1> { first = x; }
template <int i = 2> auto SetValue(T2 x) -> std::enable_if_t<i == 2> { second = x; }

I use SFINAE on the return-type to remove the function from consideration unless the template-argument is right. 除非模板参数正确,否则我在返回类型上使用SFINAE将功能从考虑中删除。

For this particular situation, you should definitely prefer std::pair or std::tuple . 对于这种特殊情况,您绝对应该首选std::pairstd::tuple

You can simply overload SetValue() (provided T1 and T2 can be distinguished, if not you have a compile error): 您可以简单地重载SetValue() (如果没有编译错误,则可以区分提供的T1T2 ):

void SetValue(T1 x)
{ first=x; }

void SetValue(T2 x)
{ second=x; }

Then, the compiler with find the best match for any call, ie 然后,编译器找到与任何调用都匹配的最佳匹配,即

Pair<int,double> p;
p.SetValue(0);    // sets p.first
p.SetValue(0.0);  // sets p.second

With GetValue() , the information of which element you want to retrieve cannot be inferred from something like p.GetValue() , so you must provide it somehow. 使用GetValue() ,无法从p.GetValue()类的p.GetValue()推断出要检索哪个元素的信息,因此您必须以某种方式提供它。 There are several options, such as 有几种选择,例如

template<typename T>
std::enable_if_t<std::is_same<T,T1>,T>
GetValue() const
{ return first; }

template<typename T>
std::enable_if_t<std::is_same<T,T2>,T>
GetValue() const
{ return second; }

to be used like

auto a = p.GetValue<int>();
auto b = p.GetValue<double>();

but your initial version is good enough. 但是您的初始版本就足够了。

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

相关问题 C++ 有没有办法为同一参数使用不同类型初始化 class? - C++ Is there a way to initialize a class using different types for the same argument? C++ 根据运行时参数返回不同的派生模板类 - C++ return different derived template class based on runtime argument 如何根据 C++ 中的条件返回两个不同的 lambda function? - How to return two different lambda function depending on condition in C++? 根据传递给构造函数的参数,C++ 方法是否可以具有不同的返回类型? - Can a C++ method have different return types depending on parameters passed to the constructor? C++:在 class 图中用两种不同的可能类型表示变量,具体取决于预处理器指令 - C++: Represent variable in class diagram with two different possible types depending on preprocessor directive 如何从C++中的switch语句返回不同类型的变量 - How to return different types of variable from switch statement in c++ C ++如何从具有不同返回类型的接口继承多个? - C++ How to multiple inherits from interfaces with different return types? 如何从 c++ 中的 function 返回不同的类型? - how return different types from function in c++? C++ 11中如何根据constexpr参数返回不同类型? - How to return different types according to constexpr parameter in C++ 11? 如何让 C++ function 返回不同的类型? - How to let a C++ function return different types?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM