【问题标题】:How does make_pair know the types of its args?make_pair 如何知道其 args 的类型?
【发布时间】:2010-04-19 22:59:35
【问题描述】:

MSVC++“实用程序”标头中make_pair的定义是:

模板 内联 对<_ty1 _ty2> make_pair(_Ty1 _Val1, _Ty2 _Val2) { // 由参数组成的返回对 返回(对<_ty1>(_Val1,_Val2)); }

尽管没有将参数类型放在尖括号中,但我一直使用 make_pair:

map theMap ; theMap.insert(make_pair("string", 5));

我不应该告诉make_pair第一个参数是std::string而不是char*吗?

它是怎么知道的?

【问题讨论】:

    标签: c++ stdmap std-pair


    【解决方案1】:

    函数模板调用通常可以通过参数推导避免显式模板参数(即make_pair&lt;…&gt;),这是由C++03 §14.8.2 定义的。摘录:

    当一个函数模板 专业化被引用,所有 模板参数必须有 价值观。这些值可以是 明确指定,或在某些情况下 案例,由使用推断。

    具体规则有点复杂,但通常只要你只有一个通常足够合格的专业,它“就行了”。

    您的示例使用了两步推演和一个隐式转换。

    • make_pair 返回 pair&lt;char const*, int&gt;
    • 然后template&lt;class U, classV&gt; pair&lt;string,int&gt;::pair( pair&lt;U,V&gt; const &amp; ) 启动U = char*, V = int 并执行成员初始化,
    • 调用string::string(char*)

    【讨论】:

    • 第一部分有误导性,但第二部分是正确的:你不告诉make_pair 类型,pair 中的模板化构造函数负责类型转换。
    • @David:你能更具体地说明什么是误导吗?有两个推演步骤,其中一个是make_pair 弄清楚自己的返回类型。
    • “这是模板参数推导的完美示例”...问题是make_pair如何推导出第一个元素是string,答案是它不是,而不是它是一个“完美的例子”。涉及一个两步过程,第二步是执行转换的一步。我赞成,因为问题的后半部分是准确和正确的。 (可能误导是错误的词和 误导 本身:))。
    【解决方案2】:

    它没有。 make_pair 生成了一对(或者可能是一对)。

    但是,如果您注意到在 pair 的实现中有一个模板化的复制构造函数:

    
    template < typename Other1, typename Other2 > 
    pair(pair<Other1,Other2>& other) 
      : first(other.first), second(other.second)
    {}
    

    这可能以稍微不同的方式实现,但相当于同一件事。由于此构造函数是隐式的,因此编译器会尝试从您的 pair 中创建 pair<:string> - 因为必要的类型是可转换的。

    【讨论】:

    • +0 pair 的构造函数是否隐式都没有关系。我明确表示它仍然有效。
    • 详细来说,构造函数在初始化列表中被显式调用;没有发生隐式转换。
    • @eddy - 仅仅因为您明确表示并且代码“有效”并不意味着发生的事情就是您认为发生的事情。尝试仅使用初始构造函数和像 pair 那样的显式转换复制构造函数来创建自己的类型,例如 pair。除非您的编译器损坏,否则您会发现“显式”会使代码失败。 @GMan - 我说的是 pair 的构造函数,而不是初始化列表中 std::string 的构造调用。
    • @eddie - 扩展,显式关键字的全部目的是通过调用一个函数来禁止不希望的类型转换,该函数期望类型 X 和类型 Y 可以构造 X。换句话说,它意味着不允许讨论的代码类型。因此,如果您确实在 std::pair 中明确了该构造函数并且调用仍然有效,那么除了您认为正在发生的事情之外,还有一些事情正在发生。
    • @noah - 我确实按照您的建议创建了自己的一对,并明确了构造函数。它不依赖于隐式转换。请参阅@potatohead 的答案。
    【解决方案3】:

    make_pair()正好存在,所以可以通过参数类型推导来确定模板参数类型。

    看到这个问题:Using free function as pseudo-constructors to exploit template parameter deduction

    【讨论】:

      【解决方案4】:

      它依赖于 std::string 的构造函数接受 const char* 的事实。 std::string 的这个构造函数是否显式都没关系。模板扣除类型,使用pair的拷贝构造函数进行转换。对构造函数是否显式也无关紧要。

      如果你把std::string的构造函数变成:

      class string
      {
      public:
          string(char* s)
          {
          }   
      };
      

      你得到这个错误:

      /usr/include/c++/4.3/bits/stl_pair.h: In constructor ‘std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = const char*, _U2 = int, _T1 = const string, _T2 = int]’:
      foo.cpp:27:   instantiated from here
      /usr/include/c++/4.3/bits/stl_pair.h:106: error: invalid conversion from ‘const char* const’ to ‘char*’
      /usr/include/c++/4.3/bits/stl_pair.h:106: error:   initializing argument 1 of ‘string::string(char*)’
      

      构造函数如下所示:

        template<class _U1, class _U2>
          pair(const pair<_U1, _U2>& __p)
          : first(__p.first),
            second(__p.second) { }
      

      复制构造函数如下所示:

      template<class _U1, class _U2>
      pair(const pair<_U1, _U2>& __p)
          : first(__p.first),
            second(__p.second) { }
      

      【讨论】:

      • 从技术上讲,标准规定类X 的复制构造函数采用X&amp;X const &amp; 类型的单个参数。模板化构造函数永远不能是复制构造函数。 (也就是说,如果类X 定义了template &lt;typename T&gt; X( T&amp; );,即使X x( f() );f 返回X 匹配模板化的协程函数,编译器将使用隐式生成的复制构造函数而不是显式定义的模板化构造函数。)
      猜你喜欢
      • 2019-11-10
      • 1970-01-01
      • 2019-01-03
      • 2021-07-04
      • 1970-01-01
      • 1970-01-01
      • 2012-09-15
      • 1970-01-01
      • 2016-01-03
      相关资源
      最近更新 更多