类中的模板函数

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&lt;int&gt;dat&lt;char&gt;dat&lt;double&gt; 使用标志来确定类型是否混淆,并可能导致相当多的错误。 我什么都没尝试,我的教授希望我这样尝试。我必须为其中包含不同类型节点的链接队列编写一个类。 【参考方案1】:

准确地说,你希望函数的返回类型 取决于它是对象中的id 字段;换句话说, 动态的。模板在编译时被解析,所以它们 在这里帮不上忙。你必须返回类似的东西 boost::variantboost::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&amp; deflt).【参考方案5】:

VS2012 说 “错误 C2783: 'T Data::dat(void)' : 无法推断出 'T' 的模板参数”

你只需要告诉函数datT是什么:

cout<<test.dat<int>();

如果你传递一个模板参数,可以推断模板类型,但它不能猜测返回类型。

【讨论】:

他根据对象中的一个字段返回不同的类型。换句话说:返回类型应该取决于运行时数据。我认为模板在这里没有帮助。 我同意 - 这(以及类似的答案)将处理当前的编译器错误,但前提是错误的。我们应该问问 OP 到底想做什么。

以上是关于类中的模板函数的主要内容,如果未能解决你的问题,请参考以下文章

C++模板类中的成员函数以及模板函数在类外定义的方式

在派生类中使用模板基类模板构造函数

模板类中的构造函数继承 (C++11)

在 C++ 中的多个类中使用模板类

模板类中的友元函数

如何管理具有递归函数调用的模板类中的数组(以数组的长度作为参数)?