我有这段代码:
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;
}
};
我如何实现两个单一方法SetValue()
和GetValue()
,而不是我所拥有的四个方法,它们取决于应该使用的泛型类型的参数?例如,我认为GetValue()
方法可以采用1或2的int
参数,并根据数字返回T1
或T2
类型的变量。但我事先并不知道返回类型,所以无论如何都要解决这个问题?
答案 0 :(得分:1)
不确定你想要什么,而不是你所要求的,但......
我建议使用如下定义的包装器基类
template <typename T>
class wrap
{
private:
T elem;
public:
void set (T const & t)
{ elem = t; }
T get () const
{ return elem; }
};
现在你的班级可以定义为
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(); }
};
或者,如果您可以使用C ++ 11和可变参数模板,并且如果您定义类型特征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; };
您可以更灵活地定义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(); }
};
现在set()
的参数可以选择正确的基类和正确的基本元素
Pair<int, long> p;
p.set(0); // set the int elem
p.set(1L); // set the long elem
否则,通过索引,你可以写
p.set<0U>(3); // set the 1st (int) elem
p.set<1U>(4); // set the 2nd (long) elem
不幸的是,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
显然,当T1
等于T2
以下是(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
}
答案 1 :(得分:0)
C ++是静态类型的,因此给出的参数必须是模板参数而不是函数参数。
虽然它看起来只是用户的一个功能,但实际上只有两个。
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; }
我在返回类型上使用SFINAE来删除函数,除非模板参数是正确的。
答案 2 :(得分:0)
对于这种特殊情况,您绝对应该更喜欢std::pair
或std::tuple
。
你可以简单地重载SetValue()
(提供T1
和T2
可以区分,如果不是你有编译错误):
void SetValue(T1 x)
{ first=x; }
void SetValue(T2 x)
{ second=x; }
然后,编译器找到任何调用的最佳匹配,即
Pair<int,double> p;
p.SetValue(0); // sets p.first
p.SetValue(0.0); // sets p.second
使用GetValue()
,无法从p.GetValue()
之类的内容推断出您要检索的元素的信息,因此您必须以某种方式提供它。有几个选项,例如
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; }
像
一样使用auto a = p.GetValue<int>();
auto b = p.GetValue<double>();
但是你的初始版本还不错。