C++ 具有聚合初始化和模板推断 背景:

C++ 具有聚合初始化和模板推断 背景:,c++,templates,c++17,type-deduction,aggregate-initialization,C++,Templates,C++17,Type Deduction,Aggregate Initialization,C++17有两大特性:聚合初始化和类的模板类型推断。聚合初始化允许您在不复制或移动字段的情况下实例化字段,而模板类型推断则使您不必指定参数的类型 下面代码中的包装器类就是一个例子。只要HAVE_MOVE_和_COPY未定义,它就有聚合初始化,但模板类型推断不起作用 另一方面,如果定义了HAVE\u MOVE\u和\u COPY,则模板类型推断有效,但聚合初始化中断。我怎么能两者兼得呢 #include <cstdio> #include <utility> templa

C++17有两大特性:聚合初始化和类的模板类型推断。聚合初始化允许您在不复制或移动字段的情况下实例化字段,而模板类型推断则使您不必指定参数的类型

下面代码中的包装器类就是一个例子。只要HAVE_MOVE_和_COPY未定义,它就有聚合初始化,但模板类型推断不起作用

另一方面,如果定义了HAVE\u MOVE\u和\u COPY,则模板类型推断有效,但聚合初始化中断。我怎么能两者兼得呢

#include <cstdio>
#include <utility>

template<class T> 
struct Wrapper {
    T value;
   #ifdef HAVE_MOVE_AND_COPY
    Wrapper(T const & val) : value{val} {}
    Wrapper(T && val) : value{std::move(val)} {}
   #endif
    Wrapper(Wrapper const &) = default;
    Wrapper(Wrapper &&) = default;
    

};

struct VocalClass {
    VocalClass() { puts("VocalClass()"); }
    VocalClass(VocalClass const&) { puts("VocalClass(VocalClass const &)"); }
    VocalClass(VocalClass &&) { puts("VocalClass(VocalClass &&)"); }
};

int main() {
    Wrapper<VocalClass> w { VocalClass() }; 

   #ifdef TRY_DEDUCTION
    Wrapper w2 { VocalClass() }; 
   #endif
}
具有模板推断,但VocalClass被移动: 如果没有“移动”和“复制”,模板类型扣减将中断: 问题
有什么方法可以同时进行模板类型推断和聚合初始化吗?

首先,术语是类模板参数推断

第二,您需要的是一个扣除指南:

如果没有构造函数,您需要一些其他方法来指导推导。这就是它的用途,它允许:

Wrapper w{4}; // ok, Wrapper<int>

首先,术语是类模板参数推断

第二,您需要的是一个扣除指南:

如果没有构造函数,您需要一些其他方法来指导推导。这就是它的用途,它允许:

Wrapper w{4}; // ok, Wrapper<int>

你对“聚合”一词的含义有误解

首先,您正在做的是列表初始化。如果实例的类型是聚合,则列表初始化将仅聚合初始化实例。聚合初始化允许您按照初始值设定项列表的顺序初始化基类和/或类的成员

发件人:

聚合是以下类型之一:

数组类型 类类型,通常为struct或union,具有 不允许用户提供、继承或显式构造函数显式默认或删除构造函数 自C++17基类以来,没有虚拟、私有或受保护的 没有虚拟成员函数 没有默认的成员初始值设定项 第二点适用于这里。由于您有一个用户提供的构造函数,在定义have_MOVE_和_COPY时,该构造函数是由用户编写的,而不是由编译器生成的,因此您的类型不是聚合,编译器将只查找构造函数来初始化您的实例


Barry讲述了如何使用类模板参数推断进行聚合的其余部分。

您对术语聚合的含义有误解

首先,您正在做的是列表初始化。如果实例的类型是聚合,则列表初始化将仅聚合初始化实例。聚合初始化允许您按照初始值设定项列表的顺序初始化基类和/或类的成员

发件人:

聚合是以下类型之一:

数组类型 类类型,通常为struct或union,具有 不允许用户提供、继承或显式构造函数显式默认或删除构造函数 自C++17基类以来,没有虚拟、私有或受保护的 没有虚拟成员函数 没有默认的成员初始值设定项 第二点适用于这里。由于您有一个用户提供的构造函数,在定义have_MOVE_和_COPY时,该构造函数是由用户编写的,而不是由编译器生成的,因此您的类型不是聚合,编译器将只查找构造函数来初始化您的实例


Barry介绍了如何使用类模板参数推断生成聚合的其余部分。

如果您的类型具有用户声明的析构函数,则该类型不是聚合,在这两种情况下都是如此,因此无法进行聚合初始化。好的。我应该用什么术语来描述一个在构造时允许复制和移动elison的类?另外,包装器如何有一个用户声明的析构函数?如果您的类型有一个用户声明的析构函数,那么它就不是一个聚合,在这两种情况下都是这样,所以它不能被聚合初始化。好的。我应该用什么术语来描述一个在构造时允许复制和移动elison的类?另外,包装器如何让用户声明析构函数?
sky@sunrise:~$ c++ -DTRY_DEDUCTION -std=c++17 example.cc && ./a.out 
example.cc: In function ‘int main()’:
example.cc:27:31: error: class template argument deduction failed:
     Wrapper w2 { VocalClass() };
                               ^
example.cc:27:31: error: no matching function for call to ‘Wrapper(VocalClass)’
example.cc:12:5: note: candidate: ‘template<class T> Wrapper(Wrapper<T>&&)-> Wrapper<T>’
     Wrapper(Wrapper &&) = default;
     ^~~~~~~
example.cc:12:5: note:   template argument deduction/substitution failed:
example.cc:27:31: note:   ‘VocalClass’ is not derived from ‘Wrapper<T>’
     Wrapper w2 { VocalClass() };
                               ^
example.cc:11:5: note: candidate: ‘template<class T> Wrapper(const Wrapper<T>&)-> Wrapper<T>’
     Wrapper(Wrapper const &) = default;
     ^~~~~~~
example.cc:11:5: note:   template argument deduction/substitution failed:
example.cc:27:31: note:   ‘VocalClass’ is not derived from ‘const Wrapper<T>’
     Wrapper w2 { VocalClass() };
                               ^
example.cc:5:8: note: candidate: ‘template<class T> Wrapper(Wrapper<T>)-> Wrapper<T>’
 struct Wrapper {
        ^~~~~~~
example.cc:5:8: note:   template argument deduction/substitution failed:
example.cc:27:31: note:   ‘VocalClass’ is not derived from ‘Wrapper<T>’
     Wrapper w2 { VocalClass() };
                  
template<class T> 
struct Wrapper {
    T value;
};

template <typename T>
Wrapper(T) -> Wrapper<T>; // this is a deduction guide
Wrapper w{4}; // ok, Wrapper<int>