【问题标题】:conversion operator with template functions带有模板函数的转换运算符
【发布时间】:2013-08-07 14:45:55
【问题描述】:

我有一个带有std::string 的转换运算符的类。除了接收std::basic_string<T>(模板为T)的函数之外,它适用于所有内容。

#include <string>
struct A{
  operator std::string(){return std::string();}
};

void F(const std::basic_string<char> &){}
template<typename T> void G(const std::basic_string<T> &) {}

int main(){
  A a;
  F(a); // Works!
  G(a); // Error!
  return 0; // because otherwise I'll get a lot of comments :)
}

我收到的错误是

error: no matching function for call to 'G(A&)'                                     
note: candidate is:
note: template<class T> void G(const std::basic_string<_CharT>&)

现在,我知道我可以将G 定义为结构A 中的朋友,它会起作用,但我的问题是很多已经存在并接收std::basic_string&lt;T&gt; 的stl 函数(例如, operator&lt;&lt; 打印函数,或比较运算符,或许多其他函数。

我真的希望能够像使用std::string 一样使用A。有没有办法做到这一点?

【问题讨论】:

  • 问题是需要为G 推导出T,并且它不能那样工作(考虑转换函数)。 G&lt;char&gt;(a); 会起作用,但我想这不是你想要的。
  • 是的,G((std::string)a) 也可以,但两者都不是很有效。我想要比仅仅添加 str() 成员函数而不是转换运算符更短/更好的东西
  • 你最好创建一个 ToString 方法。
  • @NeilKirk - 当然,但这意味着转换运算符在许多情况下是无用的。更糟糕的是,这意味着我根本不能使用转换运算符(即使对于非模板函数),因为有时他必须使用 ToString 方法而有时他不会让类的用户感到困惑t.
  • return 0; // because otherwise I'll get a lot of comments :) 包含它您可能会得到更多。它是多余的,所以我会省略它。

标签: c++ templates stl


【解决方案1】:

我真的希望能够像使用 std::string 一样使用 A。有没有办法做到这一点?

是的,但你确定你真的想要这个吗?解决办法是:

struct A : public std::string {
};

但请记住,std::string 没有virtual 析构函数,因此不能多态使用。 您已被警告!!!

str() 是一个更好的解决方案,当您想将 A 传递给采用 std::basic_string&lt;T&gt; 的函数时,它可以让您明确。

【讨论】:

  • 这实际上是一个有趣的选择。我不打算多态地使用它,老实说,这并不是我真正想要/需要的——但我不得不考虑也许我可以让它工作! 编辑 - 是否可以从const std::string 继承?
  • @cluracan 你不能从“const”的东西继承。
  • @NeilKirk - 太糟糕了:(因为这正是我想要的......(也许,还没有真正考虑过)
  • @cluracan 你会经历许多复杂而丑陋的想法,直到你意识到有些事情不值得费心,而 ToString 是;)
  • @NeilKirk - 这是我目前使用的解决方案(虽然我称它为 str,因为它更短,这就是 stl 使用的)。我只是真的希望有一些我不知道的东西。可悲的是,这些问题仍然存在于 C++ 中,只是因为你想制作一些“更通用”的东西(stringchar 上模板化)你失去了功能(能够做一个operator string
【解决方案2】:

编译器无法推断出那么远;您要么必须显式调用强制转换运算符,要么显式指定模板参数:

G(static_cast<std::string>(a));
G<char>(a); 

要理解为什么编译器不能同时进行自定义转换和模板参数推导,我们来看这个例子:

template<typename T>
struct Number {
    Number(double n) {};
    Number(int n) {};
};

struct A{
  operator Number<double>(){return Number<double>(1.);}
  operator Number<int>(){return Number<int>(1);}
};

template<typename T> void G(Number<T>& number) { }

int main(){
  A a;
  G(a); // What do I do ?!
  return 0;
}

在这种情况下编译器应该做什么?

【讨论】:

  • 但这两个选项都比使用特定的str() 成员函数进行转换更糟糕(丑陋)。所以在真正意义上,这种缺乏使得转换运算符几乎无用(对于像string 这样的模板)。真的没有办法解决吗?
  • 关于您的编辑 - 不是一个很好的例子。现在有 2 个选项,编译器应该说“嘿,有两个选项!”就像有两个选项时一样(即使对于非模板内容和完全像intlong 一样工作的转换)。问题是,虽然在我的例子中有一个选项,但编译器找到了 0 个选项。
  • @cluracan 编译器没有足够的约束来执行简单的一级推导。并且让编译器进行多层次推理会产生很多副作用。
【解决方案3】:

执行模板参数推导时不考虑用户定义的转换。

G 的显式特化将起作用。

G<char>(a);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-10
    • 2019-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-06
    • 1970-01-01
    相关资源
    最近更新 更多