【问题标题】:What is proper syntax to overload cast operator to std::map?将强制转换运算符重载到 std::map 的正确语法是什么?
【发布时间】:2018-08-28 17:14:29
【问题描述】:

这是一道 C++03 题。

在下面的代码中,class Foo 是一个模板类,其中包含从 std::stringT 成员函数的映射。 class Bar 包含一个 Foo<Bar> 类型的成员变量。我想在class Foo 中实现一个 cast-to-map 运算符,以便它是“直通”的,并且可以像 contained 映射一样使用,没有明确的 getter,但是我无法确定强制转换运算符的正确语法。

#include <iostream>
#include <map>
#include <string>

#define FOO 1

template <typename T>
class Foo
{
public:
#if FOO
  operator
  std::map< std::string, void (T::*)( const std::string&,
                                      const std::string& ) >&()
  {
    return member_;
  }
#else
  Foo() : member_( 42 ) {}
  operator int&() { return member_; }
#endif

private:
#if FOO
  std::map< std::string, void (T::*)( const std::string&,
                                      const std::string& ) > member_;
#else
  int member_;
#endif
};

class Bar
{
public:
#if FOO
  void func()
  {
    fb_["a"] = &Bar::abc;
  }
#else
  void func()
  {
    std::cout << fb_ << std::endl;
  }
#endif

  void abc( const std::string& key, const std::string& val )
  {
    std::cout << key << ": " << val << std::endl;
  }

private:
  Foo<Bar> fb_;
};

int main( int argc, char* argv[] )
{
  Bar b;
  b.func();
  return 0;
}

编译错误很神秘;我不知道该怎么做:

>g++ --version
g++ (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

>g++ -g main.cpp 
main.cpp: In member function 'void Bar::func()':
main.cpp:33:8: error: no match for 'operator[]' (operand types are 'Foo<Bar>' and 'const char [2]')
     fb_["a"] = &Bar::abc;

您可以看到我玩弄了一个转换为整数的运算符,它工作得很好,但它的语法对于我来说可能过于简单,无法推断为一个转换为映射的运算符。

有人可以帮忙看看正确的语法吗?

【问题讨论】:

  • typedef 是你的朋友。也就是说,是否对下标运算符的目标对象执行隐式转换仍然存在问题。
  • @BenVoigt - 好吧,我刚试过typedef std::map&lt; std::string, void (T::*)( const std::string&amp;, const std::string&amp; ) &gt; FooMap;,这有助于提高可读性。但这只会给我operator FooMap&amp;() { ... } 带来相同的编译错误。你还有什么建议我错过的吗?
  • 不,这就是我建议typedef 的全部意思。您的代码无法编译的原因是下标运算符 x[y] 被转换为 x.operator[](y) 并且可以在参数上进行转换,但不能在目标对象上进行转换。你想要的就是不可能的,你需要一个转发功能。
  • @BenVoigt 是否有进一步阅读您所描述的内容? (或者也许您可以发布答案?在此评论部分的限制中可能很难捕获详细信息?)我可能不太了解您的答案,因为我仍然不明白为什么 cast-to-int 运算符有效当cast-to-map没有时。与下标运算符的参与有关...?我没有看到全貌。
  • 我正在寻找一个现有的清晰解释,所以我不必编写它;)顺便说一句,您的代码是否使用 FOO undefined 和 std::cout &lt;&lt; fb_["abc"]; 编译?这对于实际的 int 是合法的(因为字符串文字不够长,所以 42 的值会在运行时中断)。

标签: c++ operator-overloading typecast-operator


【解决方案1】:

@BenVoight 引导我认识到这一点:operator[] 函数调用应用于“原始”对象,而不是“传递”对象。 IE。即使我在class Foo 中实现了一个类型转换为映射的运算符,我随后调用的operator[] 仍然适用于Foo 对象,而不是我的Foo 对象被类型转换的std::map .

这给了我一个想法,也许我需要重载operator[],我这样做显然是成功的:

#include <iostream>
#include <map>
#include <string>

template <typename T>
class Foo
{
public:
  typedef void (T::*TFunc)( const std::string&, const std::string& );
  typedef std::map< std::string, TFunc > FooMap;
  operator FooMap&()
  {
    return member_;
  }

  TFunc& operator []( const std::string& str )
  {
    return member_[ str ];
  }

private:
  FooMap member_;
};

class Bar
{
public:
  void func()
  {
    fb_["a"] = &Bar::abc;
  }

  void callFunc( const std::string& str, const std::string arg1,
                 const std::string& arg2 )
  {
    (this->*fb_[ str ])( arg1, arg2 );
  }

  void abc( const std::string& key, const std::string& val )
  {
    std::cout << key << ": " << val << std::endl;
  }

private:
  Foo<Bar> fb_;
};

int main( int argc, char* argv[] )
{
  Bar b;
  b.func();
  b.callFunc( "a", "hello", "world" );
  return 0;
}

输出:

>g++ -g main.cpp 
>./a.out    
hello: world

【讨论】:

  • 是的,就是这样。起初,我将您的“不想要 getter 函数”解释为意味着您知道可能的转发 operator[],但转念一想,我猜您的意思是 _fb[x] vs _fb.get()[x]
猜你喜欢
  • 2018-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 2018-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多