【问题标题】:Eliminating the unwanted case for a template class消除模板类的不需要的情况
【发布时间】:2015-09-26 21:44:15
【问题描述】:

我使用模板类类型数据类型作为类方法的参数。在那种方法中,我正在计算参数的差异并打印它。这只是实际项目中的示例代码。

Header.h

#ifndef Header_h
#define Header_h

#include <iostream>
#include "string.h"

template <class T>
class Student
{
public:
    Student(T);
    void calcDifference(int idx, T val1, T val2);

};
#endif

ma​​in.cpp

#include <iostream>
#include "Header.h"

using namespace std;

template <class T>
void Student<T>::calcDifference(int idx, T val1, T val2)
{
    T difference  = val1 - val2;
    cout<<"\nDifference values: "<<difference<<endl;

}

template <class T>
Student<T>::Student(T)
{
    cout<<"constructor  called";
}


int main(int argc, const char * argv[])
{

    Student<int> oStudent(10);
    oStudent.calcDifference(1, 12, 10);


    //THIS FOLLOWING OBJECT CREATES ERROR BECAUSE IT IS TRYING TO PASS STRING TYPE
    Student<string> o2_Student("hi");
    o2_Student.calcDifference(1, "aaa", "aa");

    return 0;
}

问题: 因为,我正在尝试计算calcDifference() 中的参数之间的差异,main() 中的第二个对象试图传递字符串会产生问题。这是因为无法对字符串进行差分运算(至少直接)。

错误: /Users/siddharth/coding/cplusplus/xCode/CPPCodes/InterviewTest/InterviewTest/main.cpp:9:26: Invalid operands to binary expression ('std::__1::basic_string&lt;char&gt;' and 'std::__1::basic_string&lt;char&gt;')

我需要什么:我希望代码保持通用(对于我无法实际更改的调用函数)。我想找到一些解决方案,这样我就不会得到这个编译器错误,如果传递的参数是字符串类型,那么calcDifference() 应该打印一个语句(如“不允许使用字符串数据类型”)并返回调用函数。我可以在calcDifference() ONLY 中进行更改,因为在实际项目中我无法控制调用函数。我认为在这种情况下异常处理无济于事,因为它有助于捕获运行时错误,但在这种情况下,由于调用函数试图传递字符串(模板 T 被设为字符串),所以我得到了编译时错误。

PS:我无法对这个结构进行任何更改,这意味着我什至无法更改参数的数量等。我只能在方法 calcDifference() 中进行更改。

【问题讨论】:

  • 你能在calcDifference 中添加一个额外的参数,告诉它如何处理这两个对象吗?它可以默认为std::less,但允许您提供自己的功能。
  • 不,我不能对这个结构做任何改变。我只能在方法内部进行更改。
  • 您希望如何“处理此案”?你期望发生什么? (你不想要编译时错误,对吧?)
  • calcDifference 内部,您可以调用一个免费的辅助函数来计算差异并适当地重载它。
  • 可能是,我没有找到合适的标题。我的意思是,当调用函数试图传递字符串时,我该如何处理。

标签: c++ template-classes


【解决方案1】:

线

T difference  = val1 - val2;

val1 - val2 没有为一个类型定义时是一个问题。 T = std::string 时就是这种情况。这就是编译器所抱怨的。

解决此问题的一种方法是使用帮助程序 struct 模板,该模板适用于使用通用逻辑的大多数类型,但允许您将其专门用于未定义 val1 - val2 的类型。

定义一个助手struct

template <typename T> struct difference
{
    T operator()(T val1, T val2) const { return val1 - val2; }
};

而不是使用

T difference  = val1 - val2;

使用

T diff  = difference<T>()(val1, val2);

difference 专门用于std::string

template <> struct difference<std::string>
{
    std::string operator()(std::string const& val1,
                           std::string const& val2) const
    {
       // Figure what it means to compute the difference
       // between two strings for your application.
        return stringDifference(val1, val2);
    }
};

【讨论】:

  • 我需要在calcDifference() 中同时使用structs 吗?那么当我将字符串作为参数时,它会自动调用相应的函数吗?
  • 而不仅仅是转储代码,您应该解释为什么您认为这可以解决 OP 的问题。我没看到。
  • @skm,是的。这就是创建difference 作为类模板的目的。
  • @LightnessRacesinOrbit,我误解了“我没有看到它。”
【解决方案2】:

我认为有一个非常简单的解决方案:模板专业化。

只需为Tbeeing string添加以下差异方法的专业化:

template <>
void Student<string>::calcDifference(
    int idx, string const & val1, string const & val2)
{
    cout << "Computing string difference (" << val1 << " - " << val2 
         << ") is undefined!" << endl;
}

当您在strings 上调用calcDifference 时,首选实现的专用版本并因此使用。我已经完成了您的示例here。这样,您无需更改任何调用函数。

进一步说明:我添加了一些const &amp; 用于处理模板参数。一般而言,这是一种很好的做法,但对于模板来说是必不可少的:通过T 的一些可能很大,因此仅为了计算差异而复制成本很高。

【讨论】:

  • 谢谢,但正如我已经提到的,我只想在 calcDifference() 的主体内进行更改,所以,这个解决方案对我没有帮助(我的意思是,这很好,但我正在寻找一个这样我就不需要添加任何其他方法/功能)。
猜你喜欢
  • 1970-01-01
  • 2018-09-08
  • 2011-09-18
  • 2011-08-29
  • 1970-01-01
  • 2019-04-29
  • 1970-01-01
  • 1970-01-01
  • 2022-11-27
相关资源
最近更新 更多