【问题标题】:How to implement typed strings in C++11?如何在 C++11 中实现类型化字符串?
【发布时间】:2014-12-28 12:43:32
【问题描述】:

在我的项目中,在同一范围内有很多不同含义的字符串,比如:

std::string function_name = "name";
std::string hash = "0x123456";
std::string flag = "--configure";

我想通过它们的含义来区分不同的字符串,以便与函数重载一起使用:

void Process(const std::string& string_type1);
void Process(const std::string& string_type2);

显然,我必须使用不同的类型:

void Process(const StringType1& string);
void Process(const StringType2& string);

但是如何以优雅的方式实现这些类型呢?我能得到的只有这个:

class StringType1 {
  std::string str_;
 public:
  explicit StringType1(const std::string& str) : str_(str) {}
  std::string& toString() { return str_; }
};

// Same thing with StringType2, etc.

你能建议更方便的方法吗?


重命名函数没有意义,因为主要目标是不要错误地传递一种字符串类型而不是另一种:

void ProcessType1(const std::string str);
void ProcessType2(const std::string str);

std::string str1, str2, str3;

// What should I pass where?..

【问题讨论】:

  • “按含义区分不同的字符串”您能详细说明一下它们的含义吗?对我来说闻起来有点 XY 问题。
  • 是的,这显然是一个 XY 问题。在这种情况下,拥有自己的类来封装数据是多余的。查看策略模式。
  • @πάνταῥεῖ 只是为了看看 - 这不是很有帮助。您是否可以将建议的模式用法扩展到答案?
  • 只是 ProcessType1ProcessType2 看起来好多了。可读且简单的代码是好代码,而不是短代码。
  • 为什么一个明明是数字的散列,用字符串表示?

标签: c++ c++11 syntactic-sugar


【解决方案1】:

您可以使用我在this answer 中应用于std::vector 的类似技术。

这是std::string 的样子:

#include <iostream>
#include <string>

template<typename Tag, class T>
struct allocator_wrapper : T
{ using T::T; };

template< typename Tag,
          typename CharT = char,
          typename Traits = std::char_traits<CharT>,
          typename Allocator = std::allocator<CharT> >
using MyString = std::basic_string<CharT,Traits,allocator_wrapper<Tag, Allocator>>;

class HashTag;
class FlagsTag;

using Hash = MyString<HashTag>;
using Flags = MyString<FlagsTag>;

void foo( Hash ) {}

int main()
{
    Hash hash( "12345" );
    Flags flags( "--foo" );

    foo( hash ); // that's fine

    // you can already use them like strings in *some* contexts
    std::cout << hash << " - " << flags << std::endl;
    std::cout << ( hash == "12345" ) << std::endl;

    // but they are not compatible types:
    // won't compile:
    // foo( flags );
    // std::cout << ( hash == flags ) << std::endl;
}

【讨论】:

    【解决方案2】:

    这一切听起来有点低沉。您希望对不同对象执行不同操作的多个函数具有相同的名称。这很奇怪,因为典型的方法是为执行不同操作的函数使用相同的名称。

    不传递“错误的东西”很大程度上取决于程序员,你应该记住你在做什么,以及做什么。并在编写代码时对其进行测试,并定期运行测试以避免回归。

    另一种方法是拥有一组保存数据的类,并拥有一个通用接口,例如:

    class OptionBase
    {
    public:
       OptionBase(const std::string &s) : str(s) {}
       virtual void Process() = 0;
       virtual std::string Value() { return str; }
       virtual ~OptionBase() {}
    protected:
       std::string str;
    };
    
    class FlagOption: public OptionBase
    {
    public:
       FlagOption(const std::string& s) : OptionBase(s) {}
       void Process() override { ... do stuff here ... } 
    };
    
    class HashOption: public OptionBase
    {
    public:
        HashOption(const std::string& s) : OptionBase(s) {}
        void Process() override { ... do has stuff here ... }
    };
    
    
    class FunctionName: public OptoonBase
    {
        ... you get the idea ... 
    };
    

    现在您可以以一致的方式“处理”所有OptionBase 类型的内容,对每个内容调用相同的处理函数。但我不确定这就是你要找的。

    【讨论】:

      【解决方案3】:

      您的目标是继承,如other answer here(*)。但是你不应该从 std::string 继承。你可以找到很多关于它的讨论,例如:Inheriting and overriding functions of a std::string?

      它让您有了第一个想法,实际实现了组合的概念。

      (*) 我会在该答案中发表评论,而不是打开新答案,但我还不能发表评论。

      【讨论】:

        【解决方案4】:

        简单的方法:

        struct flag {
            string value;
        };
        struct name {
            string value;
        };
        

        您也可以通过隐式转换为字符串或其他成员函数来改进这一点。

        【讨论】:

          【解决方案5】:

          你可能想要一个带有标签参数的模板:

          template<class Tag>
          struct MyString
          {
              std::string data;
          };
          
          struct FunctionName;
          MyString<FunctionName> function_name;
          

          【讨论】:

          • 我认为在这种情况下使用函数重载并不好,但是为标签 +1 -
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-17
          • 2015-10-21
          • 1970-01-01
          • 2012-09-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多