类中的模板函数
Posted
技术标签:
【中文标题】类中的模板函数【英文标题】:Template function in class 【发布时间】:2013-11-27 12:39:38 【问题描述】:我不知道该怎么办。使用简单的类和简单的模板函数总是会出错。我阅读了所有其他解决方案,但它们没有帮助我。
在其他一些类旁边,我有一个简单的数据类:
class Data
public:
template <class T>
T dat();
int id;
union
char c;
int i;
double d;
;
;
和函数dat:
template <class T>
T Data::dat()
if(id == 1) return i;
if(id == 2) return d;
if(id == 3) return c;
如您所见,我想检查 id 并返回 int、double 或 char。 现在我尝试像这样在 main 函数中打印值:
Data test;
test.id=1;
test.i = 12;
cout<<test.dat();
但我总是收到此错误消息:
Error: Could not find a match for Data::dat<Data::T>() needed in main(int, char**).
问题出在哪里??
谢谢
【问题讨论】:
另外,模板函数实例化一个具有单一返回类型的具体函数(我在这里滥用术语,只是为了说明一点)。所以你不能返回不属于声明的返回类型的东西,无论如何都不能没有隐式转换或强制转换。模板函数的主体意味着您还没有完全掌握这个概念。 作为另一个旁注,您似乎正试图以有限的方式完成 James Kanze 提到的课程所做的事情。看看那些吧。 您真正想做什么?必须指定dat<int>
、dat<char>
或dat<double>
并使用标志来确定类型是否混淆,并可能导致相当多的错误。
我什么都没尝试,我的教授希望我这样尝试。我必须为其中包含不同类型节点的链接队列编写一个类。
【参考方案1】:
准确地说,你希望函数的返回类型
取决于它是对象中的id
字段;换句话说,
动态的。模板在编译时被解析,所以它们
在这里帮不上忙。你必须返回类似的东西
boost::variant
或boost::any
,支持这种动态
打字。
【讨论】:
非常感谢,我尝试了 boost::variant。这似乎是一个不错的解决方案,但我认为这不是我的教授希望看到的解决方案。 @ChristianManthey 如果我正确理解了这个问题,使用boost::variant
,或者重新实现类似的东西并使用它,是唯一真正的解决方案。 (并且正确地重新实现 boost::variant
之类的东西是一项艰巨的任务,而且绝对超出了学习语言的范围。)【参考方案2】:
使用这个:
cout<<test.dat<int>();
【讨论】:
如果id
为2,他想返回double
,会发生什么?【参考方案3】:
dat()
没有涉及T
的参数,因此编译器无法从调用中推导出T
,必须显式提供,例如:
cout << test.dat<int>();
另外,请记住您必须implement dat()
in the header file。
【讨论】:
【参考方案4】:我不知道该怎么办。使用简单的类和简单的模板函数总是会出错。我阅读了所有其他解决方案,但它们没有帮助我。
在我看来,您想创建一个有区别的工会。
您的实现将不起作用,因为模板函数的返回类型是在编译时确定的(即在您在 id 中设置值并尝试调用该函数之前。
解决方案:
class Data
enum value_type
int_val, char_val, double_val
discriminator; // private (the user doesn't see this)
// this replaces your id
union
char c;
int i;
double d;
value;
public:
class wrong_type_error: public std::logic_error
public:
wrong_type_error(const std::string& msg): std::logic_error(msg)
;
explicit Data(const char c)
: discriminator(Data::char_value)
, value.c(c)
explicit Data(const int i)
: discriminator(Data::int_value)
, value.i(i)
explicit Data(const double d)
: discriminator(Data::double_value)
, value.d(d)
// don't put this here: int id;
// this part can be optimized to simpler (more idiomatic) code
template<typename T> T get() const; // undefined
template<> int get() const
if(discriminator != Data::int_val)
throw wrong_type_error("Cannot return a int from Data instance");
return value.i;
template<> char get() const
if(discriminator != Data::char_val)
throw wrong_type_error("Cannot return a char from Data instance");
return value.c;
template<> double get() const
if(discriminator != Data::double_val)
throw wrong_type_error("Cannot return a double from Data instance");
return value.d;
;
客户端代码:
Data test(10.5);
cout<<test.get<double>();
综上所述,您应该考虑使用 boost::variant 或 boost::any 实例,具体取决于您的需要。
【讨论】:
您可以创建一个类型特征类,该类返回参数的类型(Data::discriminator),然后您将拥有一个(通用)get
实现。如果您必须编写更多函数(例如 get_or_default(const T& deflt)
.【参考方案5】:
VS2012 说 “错误 C2783: 'T Data::dat(void)' : 无法推断出 'T' 的模板参数”
你只需要告诉函数dat
T
是什么:
cout<<test.dat<int>();
如果你传递一个模板参数,可以推断模板类型,但它不能猜测返回类型。
【讨论】:
他根据对象中的一个字段返回不同的类型。换句话说:返回类型应该取决于运行时数据。我认为模板在这里没有帮助。 我同意 - 这(以及类似的答案)将处理当前的编译器错误,但前提是错误的。我们应该问问 OP 到底想做什么。以上是关于类中的模板函数的主要内容,如果未能解决你的问题,请参考以下文章