它只是偏好还是有特定的情况,其中一个是必要的而不是另一个?我正在参考以下变体进行初始化
T t(e); // direct initialization
T t = e; // copy initialization
c++ explicit-constructor implicit-conversion copy-initialization
鉴于以下内容:
#include <stdio.h>
class X;
class Y
{
public:
  Y() { printf("  1\n"); }             // 1
  // operator X(); // 2
};
class X
{
public:
  X(int) {}
  X(const Y& rhs) { printf("  3\n"); } // 3
  X(Y&& rhs) { printf("  4\n"); }      // 4
};
// Y::operator X() { printf("   operator X() - 2\n"); return X{2}; }
int main()
{
  Y y{};     // Calls (1)
  printf("j\n");
  X j{y};    // Calls (3)
  printf("k\n");
  X k = {y}; // Calls (3) …我有一些代码如下:
class bar;
class foo
{
public:
    operator bar() const;
};
class bar
{
public:
    bar(const foo& foo);
};
void baz() {
    foo f;
    bar b = f;   // [1]
    const foo f2;
    bar b2 = f2; // [2]
}
GCC在[2]处给出错误,但不是[1].Clang给出了两个错误,显然MSVC都没有给出错误.谁是对的?
c++ conversion-operator language-lawyer overload-resolution copy-initialization
以下代码使用 MSVC (/permissive-) 编译,但无法使用 GCC/Clang 编译 m_ptr1 和 m_ptr2。
#include <memory>
struct ForwardDeclared;
class A {
    public:
        explicit A();
        ~A();
    private:
        std::unique_ptr<ForwardDeclared> m_ptr1 = nullptr;    // not ok
        std::unique_ptr<ForwardDeclared> m_ptr2 {std::unique_ptr<ForwardDeclared>{}};    // not ok
        std::unique_ptr<ForwardDeclared> m_ptr3 {nullptr};    // ok 
        std::unique_ptr<ForwardDeclared> m_ptr4;              // ok
};
int main() {
    A a;
    return 0;
}
我的理解是该=符号会导致复制初始化,但是,由于复制省略,我预计m_ptr2仍会被初始化而不会失败。
为什么m_ptr2需要 ForwardDeclared 的析构函数并且 Clang/GCC 对此是否正确?(奖励:得出 m_ptr1 被 MSVC 错误接受的结论是否正确?)
我最近了解到,一个类中可以有多个默认构造函数。然后我编写了以下程序,使用 msvc 进行编译,但是 clang 和 gcc 都无法编译它。
\nstruct A\n{\n\xc2\xa0 explicit A(int = 10);\n\xc2\xa0 A()= default;\n};\n\nA a = {}; //msvc ok but gcc and clang fails here\n我想知道根据 C++17 标准哪个编译器是正确的。
\n海湾合作委员会 说:
\n<source>:8:8: error: conversion from \'<brace-enclosed initializer list>\' to \'A\' is ambiguous\n    8 | A a = {}; //msvc ok but gcc and clang fails here\n      |        ^\n<source>:5:3: note: candidate: \'constexpr A::A()\'\n    5 |   A()= default;\n      |   ^\n<source>:4:12: note: candidate: \'A::A(int)\'\n    4 |   explicit …在C++ 11之前,我们可以通过编写类似于A a = 1;或多或少相当的东西来进行复制初始化A a = A(1);.也就是说,首先创建临时,然后调用复制ctor.无论版本是否复制,这必须是概念上的,并且必须可以访问复制文件.
使用C++ 11中的列表初始化,我们可以通过写入来进行复制列表初始化A a = {1, 2};.在我看来,这应该或多或少相当于A a = A(1, 2);.但是,在GCC和clang上,A a = {1, 2}即使复制和移动ctor不可访问(通过声明为私有)也会编译.但是,A a = 1;如果相应的复制/移动ctor不可访问,则不会在GCC或clang上编译.所以,A a = {1, 2};似乎或多或少等同于A a{1, 2};直接列表初始化.这与实际直接列表初始化之间的区别在于,A a = {1, 2};如果采用两个整数的ctor是显式的,则不会编译.在这方面,A a = {1, 2};类似于复制初始化.
所以,我的问题是:A a = {1, 2};概念上表达式的确切语义是什么?从概念上讲,复制省略不会妨碍.
c++ copy-constructor copy-initialization c++11 list-initialization
我正在阅读直接初始化和复制初始化(§8.5/ 12)之间的区别:
T x(a);  //direct-initialization
T y = a; //copy-initialization
我从阅读有关复制初始化的内容中了解到,它需要可访问和非显式的复制构造函数,否则程序将无法编译.我通过编写以下代码验证了它:
struct A
{
   int i;
       A(int i) : i(i) { std::cout << " A(int i)" << std::endl; }
   private:
       A(const A &a)  {  std::cout << " A(const A &)" << std::endl; }
};
int main() {
        A a = 10; //error - copy-ctor is private!
}
GCC给出了一个错误(ideone)说:
prog.cpp:8:错误:'A :: A(const A&)'是私有的
到目前为止,一切都很好,重申Herb Sutter所说的,
复制初始化意味着在必要时首次调用用户定义的转换后,使用复制构造函数初始化对象,并且等效于"T t = u;"形式:
之后,我通过评论private …
可能重复:
复制和直接初始化的动机背后的动机是什么?
通过复制初始化,我的意思是这样的:
struct MyStruct
{
    MyStruct(int) {}
    MyStruct(const MyStruct&) {}
};
MyStruct s = 5; // needs *both* the int and copy constructor
尽管用C++编程多年,但我从未意识到上面的代码需要复制构造函数(感谢jogojapan).暂时一直被遗忘,因此我甚至都不知道它是否存在(至少在肤浅的层面,尽管它被优化了),直到它被指出给我.
经过大量的谷歌搜索,我了解它是如何工作的.我的问题是为什么它是这样的?
为什么标准不能使上面的例子不需要复制构造函数?是否有一些特定的案例/示例表明在这种初始化中需要复制构造函数很重要?
如果没有合理的解释为什么事情就是他们的方式,我只是把它看作是一件讨厌的神器,但如果有一些重要的东西我不想知道,我宁可不要无知.
#include <iostream>
using namespace std;
struct CL2
{
    CL2(){}
    CL2(const CL2&){}
};
CL2 cl2;
struct CL1
{
    CL1(){}
    operator CL2&(){cout<<"operator CL2&"; return cl2;}
    operator const CL2&(){cout<<"operator const CL2&"; return cl2;}
};
CL1 cl1;
int main()
{
    CL1 cl1;
    CL2 cl2 (cl1);
}
clang和gcc都提供了不明确的转换运算符,但Visual Studio编译好并打印"operator const CL2&".按标准怎么做才对?
正如我所说,将CL1转换为const CL2&是在复制初始化上下文中(作为cl2对象的直接初始化的一部分).我看过n4296草案,[over.match.copy]:
假设"cv1 T"是要初始化的对象的类型,使用T类类型,候选函数选择如下:
- T的转换构造函数(12.3.1)是候选函数.
- 当初始化表达式的类型是类类型"cv S"时,将考虑S及其基类的非显式转换函数.初始化临时绑定到构造函数的第一个参数时,其中参数的类型为"引用可能的cv-qualified T",并且在直接初始化类型的对象的上下文中使用单个参数调用构造函数"cv2 T",也考虑了显式转换函数.那些未隐藏在S中并且产生其cv非限定版本与T的类型相同或者是其派生类的类型的候选函数.返回"引用X"的转换函数返回lvalues或xvalues,具体取决于类型X的引用类型,因此被认为是为此选择候选函数的过程产生X.
即两个转换运算符被认为是返回CL2和const CL2(不仅仅是没有const的CL2)并且它仍然需要解决,哪个转换更好:CL2 - > const CL2&或const CL2 - > const CL2&.第二种情况似乎更合适.在这种情况下是否应考虑更好的资格转换?或两种情况都是身份转换?我在标准版中找不到它
在下面的代码中,我不允许声明一个显式的 ctor,因为编译器说我在复制初始化上下文中使用它(clang 3.3和gcc 4.8).我试图通过使ctor非显式,然后将复制构造函数声明为已删除来证明编译器是错误的.
编译器是错误还是有其他解释?
#include <iostream>
template <typename T>
struct xyz
{
    constexpr xyz (xyz const &)    = delete;
    constexpr xyz (xyz &&)         = delete;
    xyz & operator = (xyz const &) = delete;
    xyz & operator = (xyz &&)      = delete;
    T i;
    /*explicit*/ constexpr xyz (T i): i(i) { }
};
template <typename T>
xyz<T> make_xyz (T && i)
{
    return {std::forward<T>(i)};
}
int main ()
{
    //auto && x = make_xyz(7);
    auto && …