【问题标题】:C++11 std::is_convertible behaviour with private copy constructor具有私有复制构造函数的 C++11 std::is_convertible 行为
【发布时间】:2014-04-11 05:06:51
【问题描述】:

我试图理解 C++11 中的 std::is_convertible。根据cppreference.comstd::is_convertible<T,U>::value 应该评估为 1 且当且仅当“如果 T 类型的虚构右值可用于返回 U 的函数的返回语句中”。但是,该措辞没有说明该函数可能在何处声明。当U 的复制构造函数是私有的时,应该期待什么?当T 是一个左值引用时,我们应该期待什么?

例如,考虑以下代码:

#include <iostream>
#include <type_traits>
struct Fact_A;
struct A {
    friend struct Fact_A;
    A() = default;
    A(A&&) = delete;
private:
    A(const A&) = default;
};
struct Ref_A {
    A* _ptr;
    Ref_A(A* ptr) : _ptr(ptr) {}
    operator A& () { return *_ptr; }
};
struct Fact_A {
    static A* make_A(const A& a) { return new A(a); }
    static A f(A* a_ptr) { return Ref_A(a_ptr); }
    //static A g(A&& a) { return std::move(a); }
};
int main() {
    A a1;
    A* a2_ptr = Fact_A::make_A(a1);
    (void)a2_ptr;
    std::cout << std::is_convertible< Ref_A, A >::value << "\n"  // => 0
              << std::is_convertible< Ref_A, A& >::value << "\n" // => 1
              << std::is_convertible< A&, A >::value << "\n";    // => 0
}

我使用的是gcc-4.8.2clang-3.4(输出没有区别),我编译时使用:

{g++|clang++} -std=c++11 -Wall -Wextra eg.cpp -o eg

在这里,std::is_convertible&lt; Ref_A, A &gt; 报告0。但是,您可以看到Fact_A::f 返回了一个A 类型的对象,并且在其return 语句中使用了一个Ref_A 类型的右值。问题是A的复制构造函数是private,所以这个函数不能放在其他任何地方。当前行为是否符合标准?

第二个问题。如果我删除private,输出将变为1 1 1。最后一个1 是什么意思?什么是“A&amp; 类型的右值”?那是右值引用吗?因为你可能注意到我明确删除了A 的移动构造函数。因此,我无法声明Fact_A::g。但是,std::is_convertible&lt; A&amp;, A &gt; 仍然报告1

【问题讨论】:

    标签: c++ c++11 std language-lawyer typetraits


    【解决方案1】:

    is_convertible 在 n3485 的 [meta.rel]/4 中定义如下:

    给定以下函数原型:

    template <class T> typename
    add_rvalue_reference<T>::type create();
    

    模板特化is_convertible&lt;From, To&gt;的谓词条件 当且仅当以下代码中的返回表达式为 格式良好,包括对返回类型的任何隐式转换 功能:

    To test() {
        return create<From>();
    }
    

    在这里,您需要一个可移动/可复制的To:返回语句应用隐式转换,如果To 是类类型(T&amp; 不是类,则这需要可访问的复制/移动构造函数类型)。

    与 [conv]/3 比较

    表达式 e 可以隐式转换为类型 T 当且仅当声明 T t=e; 格式正确时,对于某些发明的临时变量 t


    如果FromT&amp;,你会得到类似的东西

    To test() {
        return create<T&>();
    }
    

    类似于std::declval,它是一个左值:表达式create&lt;T&amp;&gt;() 是/产生一个左值,因为T&amp; &amp;&amp;(通过add_rvalue_reference)被折叠成T&amp;

    【讨论】:

    • 感谢您的参考。除了你所说的,你引用的草稿部分正下方还有更多文字,特别提到了上下文问题。我会接受这个。我想剩下的是一个挥之不去的问题,即标准是否在做正确的事情。我不喜欢的是,is_convertible 似乎与To 的构造函数可访问性无关,这与FromFromTo 之间的关系无关。我可以想象我真的想知道转换是否可以在我选择的上下文中完成的情况......
    • @MateiDavid is_convertible 试图模拟 implicitly convertible 的定义,我觉得这有点不直观。该定义本身需要一个可访问的复制/移动构造函数。也许在您的上下文中,is_constructible 更有意义。
    猜你喜欢
    • 2016-11-30
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 2015-11-24
    • 1970-01-01
    • 2016-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多