[英]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
参数,并根据数字,返回T1
或T2
类型的变量。 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::pair
或std::tuple
。
You can simply overload SetValue()
(provided T1
and T2
can be distinguished, if not you have a compile error): 您可以简单地重载
SetValue()
(如果没有编译错误,则可以区分提供的T1
和T2
):
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.