【问题标题】:Cannot copy object constructed from default-constructed array无法复制从默认构造的数组构造的对象
【发布时间】:2013-07-05 10:32:34
【问题描述】:

在花费 1 或 2 个小时来隔离编译错误后,该编译错误被元编程混乱所包围,生成糟糕的编译消息,这里有一个最小且简单的示例来说明我的问题:

#include <iostream>
#include <type_traits>
#include <array>
#include <utility>
#include <tuple>

template <class Crtp, class... Types>
struct Base
{
    Base(const Types&... rhs) : 
        data(std::forward_as_tuple(rhs...)) {;}
    std::tuple<Types...> data;
};

struct Derived 
: public Base<Derived, std::array<double, 3>>
{
    template <class... Args> 
    Derived(Args&&... args) :
        Base<Derived, std::array<double, 3>>(std::forward<Args>(args)...) {;}
};

int main(int argc, char* argv[])
{
    Derived a(std::array<double, 3>({{1, 2, 3}})); 
    Derived b(a);
    Derived c(std::array<double, 3>()); 
    Derived d(c); // Not working : why ?
    return 0;
}

这是使用 g++ 4.8.1 编译的,我不明白为什么当我尝试将 c 复制到 d 而不是 a 复制到 b 时,编译器会抱怨。

这是错误:

main.cpp: In instantiation of ‘Derived::Derived(Args&& ...) [with Args = {Derived (&)(std::array<double, 3ul> (*)())}]’:
main.cpp:28:16:   required from here
main.cpp:20:73: error: no matching function for call to ‘Base<Derived, std::array<double, 3ul> >::Base(Derived (&)(std::array<double, 3ul> (*)()))’
         Base<Derived, std::array<double, 3>>(std::forward<Args>(args)...) {;}
                                                                         ^
main.cpp:20:73: note: candidates are:
main.cpp:10:5: note: Base<Crtp, Types>::Base(const Types& ...) [with Crtp = Derived; Types = {std::array<double, 3ul>}]
     Base(const Types&... rhs) : 
     ^
main.cpp:10:5: note:   no known conversion for argument 1 from ‘Derived(std::array<double, 3ul> (*)())’ to ‘const std::array<double, 3ul>&’
main.cpp:8:8: note: constexpr Base<Derived, std::array<double, 3ul> >::Base(const Base<Derived, std::array<double, 3ul> >&)
 struct Base
        ^
main.cpp:8:8: note:   no known conversion for argument 1 from ‘Derived(std::array<double, 3ul> (*)())’ to ‘const Base<Derived, std::array<double, 3ul> >&’
main.cpp:8:8: note: constexpr Base<Derived, std::array<double, 3ul> >::Base(Base<Derived, std::array<double, 3ul> >&&)
main.cpp:8:8: note:   no known conversion for argument 1 from ‘Derived(std::array<double, 3ul> (*)())’ to ‘Base<Derived, std::array<double, 3ul> >&&’

【问题讨论】:

    标签: c++ templates c++11 metaprogramming stdarray


    【解决方案1】:

    这是most vexing parse

    Derived c(std::array<double, 3>());
    

    是一个函数c的声明,它返回一个Derived并接受一个类型为的未命名参数指向不接受参数并返回std::array&lt;double, 3&gt;的函数的指针。 因此Derived d(c) 尝试从函数c 调用Derived 构造函数。这就是 GCC 在这里所说的:

    main.cpp: In instantiation of ‘Derived::Derived(Args&& ...) [with Args = {Derived (&)(std::array<double, 3ul> (*)())}]’:
    

    试试这个:

    Derived c{std::array<double, 3>{}};
    

    【讨论】:

    • 是 GCC 的 bug 还是正常的?
    • @Vincent:根据 C++ 标准,这是正常的(也就是著名的The most vexing parse)。
    【解决方案2】:

    适用于:

    Derived c(std::array<double, 3> {});
    

    编译器考虑参数在

    Derived c(std::array<double, 3>());
    

    成为一个函数。

    clang 对此给出警告:
    !!warning: parentheses were disambiguated as a function declarator.

    【讨论】:

    • 值得强调:使用 C++11 风格的初始值设定项 => 可以省去很多麻烦,包括在声明要构造对象的函数时遇到的麻烦。
    【解决方案3】:

    首先使您的 Derived 构造函数显式。 如果这无助于添加复制构造函数,但我认为这不是必需的

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-14
      • 1970-01-01
      • 2019-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-18
      相关资源
      最近更新 更多