如何避免在 std::pair 中“隐式”调用单参数构造函数

2024-05-04

最初的问题是如何与std::map<std::wstring, std::wstring> >以安全的方式进行,因为相同类型的键和值非常容易出错。所以我决定为该值创建一个简单的包装器:

    struct ComponentName
    {
      std::wstring name;

      // I want to prohibit any implicit string-ComponentName conversions!!!
      explicit ComponentName(const std::wstring& _name) : name(_name)
      {
      }

      bool operator<(const ComponentName& item_to_compare) const
      {
        return name < item_to_compare.name;
      }
    };

    typedef std::map<std::wstring, ComponentName> component_names_map;

但下面的代码运行良好!

component_names_map component_names;
// Are you sure that ComponentName's constructor cannot be called implicitly? ;)
component_names_map::value_type a_pair = std::make_pair(L"Foo", L"Bar");

它之所以有效,是因为std::pair<std::wstring, ComponentName>复制构造函数显式使用组件名称的字符串构造函数来分配std::pair<std::wstring, std::wstring>实例。这是绝对合法的操作。然而,它看起来像是 ComponentName 构造函数的“隐式”调用。

所以我知道问题的原因,但如何避免这种“隐式”wstring-ComponentName转换? 最简单的方法是不声明字符串构造函数,但这使得 ComponentName 初始化不方便。


我认为你可以通过添加部分专业化来合法地做到这一点std::pair适合您的类型:

namespace std {
    template <typename T>
    struct pair<T,ComponentName> {
       typedef T first_type;
       typedef ComponentName second_type;

       T first;
       ComponentName second;
       // The rest of the pair members:
       // ....
       // Any trick you like to make it fail with assignment/construction from 
       // pair<std::wstring, std::wstring>
    };
}

理由:

§ 17.6.4.2.1 规定了专业化的基本规则std命名空间:

“程序可以为任何标准库添加模板专门化 仅当声明依赖于 a 时,模板才到命名空间 std 用户定义类型且专业化符合标准库 原始模板的要求并没有明确 禁止”

如果您在 § 20.3 的范围内填写了课程的其余部分,我看不到任何明确的禁止可以排除这种特殊情况。


替代的、可能合法的方法:

专精std::is_constructible<ComponentName, std::wstring>这样value是假的。这被列为赋值运算符和复制构造函数的要求std::pair不同类型的。快速扫描我也看不到任何禁止,但我找不到任何说明实现是required检查要求。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何避免在 std::pair 中“隐式”调用单参数构造函数 的相关文章

随机推荐