【问题标题】:C++ template combined with STL return typesC++ 模板结合 STL 返回类型
【发布时间】:2011-12-06 11:28:05
【问题描述】:

我有一个模板化的类

template <typename T>
class Factors
{
    public:
    Factors(){};
    deque<string> stringsDeck;

    // some methods and variables here
   map <string, string> getNext();
};

getNext 方法将用作键的字符串与用作值的stringsDeck 中的字符串组合在一起,并返回map &lt;string,string&gt;。 假设我已经模板化了stringifystring2num 函数,我想要一个方法map&lt;string,Scalar&gt; getNext(),除了字符串之外的所有其他类型都可以将映射的值转换为指定的模板类型T

编译器不允许我重载两个同名但返回类型不同的方法,具体来说:

map <string, T > getNext()
{
// converts the values of getNext() return map into the specified type T
return convertedMapWithValuesOfTypeT;
}

在这种情况下有什么解决方案?我想为字符串和其他类型(基本上可以通过词法转换从字符串转换的数字类型)保持方法的名称相同

【问题讨论】:

  • 那么在调用getNext() 时如何指定是要map&lt;string, string&gt; 还是map&lt;string, T&gt;?或者你的意思是你想要map&lt;string, T&gt;,如果这两个函数是为T定义的(其中T是封闭类模板的参数)和string否则?

标签: c++ templates stl map overloading


【解决方案1】:

该语言不允许仅在 返回类型,因为在大多数情况下,不考虑返回类型 函数重载决议。在这种情况下,你真的有三个 可能的解决方案:

  • 最简单的(因此在大多数情况下是首选的解决方案)是 只是给这两个函数起不同的名字: getNextAsMapToType 和 例如getNextAsMapToString
  • 或者,您可以将函数声明为模板: 模板 std::map getNext(); 然后,将此函数专门用于std::stringT(对于 没有其他的)。用户必须指定 getNext&lt;std::string&gt;()getNext&lt;<i>...</i>&gt; 拨打他想要的电话。 一般来说,我会发现这比 以前的解决方案,但它可能适用于模板,其中 名称应该包含或至少暗示类型的名称。
  • 最后,可以在返回时模拟重载 类型,如果你不介意一些额外的复杂性。要做到这一点,你仍然 必须实现其他解决方案之一,但客户端代码 没看到。基本上,您的 getNext() 函数必须返回一个 代理,具有重载的转换函数,例如: 类代理 { 因素* myOwner; 民众: 代理(因素&所有者):myOwner(&所有者){} 运算符 std::map<:string std::string>() const { 返回 myOwner->getNextAsMapToString(); } 运算符 std::map<:string t>() const { 返回 myOwner->getNextAsMapToType(); } }; 代理 getNext() { return 代理( *this ); } 然后客户端代码可以调用getNext(),这取决于他们 处理结果,getNextAsMapToStringgetNextAsMapToType 将被调用。

【讨论】:

  • 您以某种方式发布了 HTML 而不是 Markdown。
  • 我知道我做到了,因为这是获得合理格式的唯一方法。每当我有一些复杂的事情时,我都会转向 HTML。
  • 不幸的是,这使您的答案不正确。您似乎两次超载operator std::map() const,这就是让我窥探您帖子的原因。
  • 我认为最后最好的方法是拥有两个名称不同的函数,既可读又简单。也许代码重复可能会有点伤害,但恕我直言,在这种情况下是可以接受的......
  • @JamesKanze :我个人更喜欢模板化方法,你的第二个建议。它减少了要编写的代码量,并且是最具前瞻性的。如果编写得当,您将不会有代码重复,因为从 std::string 转换为任何模板类型都可以使用 boost::lexical_cast 之类的东西完成。
【解决方案2】:

您可以使用 [typeid] 在 getNext 中添加运行时检查 (http://en.cppreference.com/w/cpp/language/typeid) 查看T 是否为字符串。

类似:

template <typename T>
class Factors
{
    public:
    Factors(){};
    deque<string> stringsDeck;

    // some methods and variables here
    map <string, T> getNext();
    {
        if (typeid(T) == typeid(string))
        {
            // Special handling for strings
        }
        else
        {
            // Do something else for other types
        }
    }
};

编辑

正如 fschoenm 所建议的,模板专业化可能更好:

template <typename T>
class Factors
{
    public:
    Factors(){};

    // some methods and variables here
    map <string, T> getNext();
};


template <>
class Factors<string>
{
    public:
    Factors(){};
    deque<string> stringsDeck;

    // some methods and variables here
    map <string, string> getNext();
};

【讨论】:

  • 如果您还可以提供在编译时评估的模板特化,为什么还要在运行时进行类型检查?
  • 如果我理解正确的话,他需要两个函数,一个返回std::map&lt;std::string, std::string&gt;,另一个返回std::map&lt;std::string, T&gt;
  • 是的,可能使用相同的名称来解决追溯兼容性问题。我想知道如何通过一些模板魔术来实现这一点......如果这不可能,我可能会将map&lt;string,string&gt; getNext() 的名称更改为getNextReturnTypeAsString()
  • @linello 您尝试过模板专业化吗?类将被命名为相同的,函数也将被命名为相同的。如果您想要通用功能,并且只是让 getNext 方法有所不同,请从通用基类继承两者。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 2018-02-21
  • 2014-12-24
  • 2014-10-26
  • 2012-07-02
相关资源
最近更新 更多