背景:
C++17 有两个很棒的特性:聚合初始化和模板类型推导(针对类)。聚合初始化允许您在不复制或移动字段的情况下实例化字段,并且模板类型推导使您不必指定参数的类型。
下面Wrapper
代码中的类就是一个例子。只要HAVE_MOVE_AND_COPY
未定义,它就有聚合初始化,但是模板类型推导不起作用。
另一方面,如果定义了HAVE_MOVE_AND_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
}
例子:
没有发生移动或复制,但您没有模板扣除:
$ c++ -std=c++17 example.cc && ./a.out
VocalClass()
有模板扣除,但VocalClass
被移动:
$ c++ -DHAVE_MOVE_AND_COPY -DTRY_DEDUCTION -std=c++17 example.cc && ./a.out
VocalClass()
VocalClass(VocalClass &&)
VocalClass()
VocalClass(VocalClass &&)
没有HAVE_MOVE_AND_COPY
, 模板类型推导中断:
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() };
问题
有什么方法可以同时进行模板类型推导和聚合初始化?