如何在 Visual Studio 2017 中支持 Variadic 模板类型
How to Support Variadic Template Types in Visual Studio 2017
使用了这个对象:
template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
template<class... Ts> overload(Ts...) -> overload<Ts...>;
struct fallback_t { template<class T> fallback_t(T&&) {} };
不幸的是,我无法在 Visual Studio 2017 年进行编译。我收到错误:
1> warning C4346: 'Ts::()': dependent name is not a type
1> note: prefix with 'typename' to indicate a type
1> note: see reference to class template instantiation 'owner::overload' being compiled
1> error C2143: syntax error: missing ';' before '...'
1> error C2059: syntax error: '...'
1> error C2238: unexpected token(s) preceding ';'
1> error C2988: unrecognizable template declaration/definition
1> error C2143: syntax error: missing ')' before '...'
1> error C2143: syntax error: missing ';' before '...'
1> error C2365: 'Ts': redefinition; previous definition was 'template parameter'
1> note: see declaration of 'Ts'
1> error C2238: unexpected token(s) preceding ';'
1> error C2059: syntax error: '...'
1> error C2059: syntax error: ')'
1> error C2955: 'owner::overload': use of class template requires template argument list
1> note: see declaration of 'owner::overload'
1> error C2664: 'void owner::bar::
::operator ()(owner::fallback_t) const': cannot convert argument 1 from 'owner::fallback_t' to 'owner::fallback_t'
1> note: use of undefined type 'owner::fallback_t'
1> note: see declaration of 'owner::fallback_t'
1> error C2672: 'owner::findObject': no matching overloaded function found
1> error C2780: 'void owner::findObject(int,const T &)': expects 2 arguments - 1 provided
1> note: see declaration of 'owner::findObject'
有什么技巧可以使 Visual Studio 尊重其中的可变参数模板?
仅在C++17中有效。尝试在 Project -> Properties -> C++ -> Language 下使用标志 /std:c++17
在 Visual Studio 2017 中编译它。请注意,C++17 从 Visual Studio 2017.3.
开始可用
这取决于三个独立的 C++17 功能:
- variadic using-declarations(支持包扩展)
- 与基数 classes
聚合
- class 模板参数推导
通常的 pre-C++17 第一个解决方法是递归继承(为简单起见省略了转发):
template<class T, class... Ts>
struct overload : T, overload<Ts...> {
using T::operator();
using overload<Ts...>::operator();
overload(T t, Ts... ts) : T(t), overload<Ts...>(ts...) {}
};
template<class T>
struct overload<T> : T {
using T::operator();
overload(T t) : T(t) {}
};
template<class...Ts>
overload<Ts...> make_overload(Ts... ts) {
return overload<Ts...>(ts...);
}
如果编译器不支持以 classes 为基数的聚合,则需要构造函数;如果编译器不支持 class 模板的模板参数推导,则需要 make_overload
。
您可以尝试在c++17 模式下编译,/std::c++17
为@S.M。已注意到;请注意,某些 C++17 功能可能会破坏现有代码。此外,正如@milesbudnek 指出的那样,截至今天,MSVC 不支持所需的功能。
如果您不能使用 C++17 模式,您可以在 c++14 中实现它。
我会做一些改变:
template <class... Fs>
struct overload_t;
// zero
template<>
struct overload_t<> {};
// >1
template <class F0, class... Frest>
struct overload_t<F0, Frest...> :
F0,
overload_t<Frest...>
{
overload_t(F0 f0, Frest... rest) :
F0(std::move(f0)), overload_t<Frest...>(std::move(rest)...)
{}
using F0::operator();
using overload_t<Frest...>::operator();
};
// 1
template <class F0>
struct overload_t<F0> : F0
{
overload_t(F0 f0) : F0(std::move(f0)) {}
using F0::operator();
};
template <class... Fs>
auto overload(Fs... fs)
{
return overload_t<Fs...>(std::move(fs)...);
}
在 C++14 中,它类似于:
template <typename ... Ts> struct overload;
template <typename T>
struct overload<T> : T
{
template <typename U>
overload(U&& u) : T(std::forward<U>(u)) {}
using T::operator();
};
template <typename T, typename ... Ts>
struct overload<T, Ts...> : overload<T>, overload<Ts...>
{
template <typename U, typename ... Us>
overload(U&& arg, Us&&... args) : overload<T>(std::forward<U>(arg)),
overload<Ts...>(std::forward<Us>(args)...) {}
using overload<T>::operator();
using overload<Ts...>::operator();
};
template<class... Ts>
overload<std::decay_t<Ts>...> make_overload(Ts&&... args)
{
return {std::forward<Ts>(args)...};
}
template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
template<class... Ts> overload(Ts...) -> overload<Ts...>;
struct fallback_t { template<class T> fallback_t(T&&) {} };
不幸的是,我无法在 Visual Studio 2017 年进行编译。我收到错误:
1> warning C4346: 'Ts::()': dependent name is not a type
1> note: prefix with 'typename' to indicate a type
1> note: see reference to class template instantiation 'owner::overload' being compiled
1> error C2143: syntax error: missing ';' before '...'
1> error C2059: syntax error: '...'
1> error C2238: unexpected token(s) preceding ';'
1> error C2988: unrecognizable template declaration/definition
1> error C2143: syntax error: missing ')' before '...'
1> error C2143: syntax error: missing ';' before '...'
1> error C2365: 'Ts': redefinition; previous definition was 'template parameter'
1> note: see declaration of 'Ts'
1> error C2238: unexpected token(s) preceding ';'
1> error C2059: syntax error: '...'
1> error C2059: syntax error: ')'
1> error C2955: 'owner::overload': use of class template requires template argument list
1> note: see declaration of 'owner::overload'
1> error C2664: 'void owner::bar::
::operator ()(owner::fallback_t) const': cannot convert argument 1 from 'owner::fallback_t' to 'owner::fallback_t'
1> note: use of undefined type 'owner::fallback_t'
1> note: see declaration of 'owner::fallback_t'
1> error C2672: 'owner::findObject': no matching overloaded function found
1> error C2780: 'void owner::findObject(int,const T &)': expects 2 arguments - 1 provided
1> note: see declaration of 'owner::findObject'
有什么技巧可以使 Visual Studio 尊重其中的可变参数模板?
仅在C++17中有效。尝试在 Project -> Properties -> C++ -> Language 下使用标志 /std:c++17
在 Visual Studio 2017 中编译它。请注意,C++17 从 Visual Studio 2017.3.
这取决于三个独立的 C++17 功能:
- variadic using-declarations(支持包扩展)
- 与基数 classes 聚合
- class 模板参数推导
通常的 pre-C++17 第一个解决方法是递归继承(为简单起见省略了转发):
template<class T, class... Ts>
struct overload : T, overload<Ts...> {
using T::operator();
using overload<Ts...>::operator();
overload(T t, Ts... ts) : T(t), overload<Ts...>(ts...) {}
};
template<class T>
struct overload<T> : T {
using T::operator();
overload(T t) : T(t) {}
};
template<class...Ts>
overload<Ts...> make_overload(Ts... ts) {
return overload<Ts...>(ts...);
}
如果编译器不支持以 classes 为基数的聚合,则需要构造函数;如果编译器不支持 class 模板的模板参数推导,则需要 make_overload
。
您可以尝试在c++17 模式下编译,/std::c++17
为@S.M。已注意到;请注意,某些 C++17 功能可能会破坏现有代码。此外,正如@milesbudnek 指出的那样,截至今天,MSVC 不支持所需的功能。
如果您不能使用 C++17 模式,您可以在 c++14
我会做一些改变:
template <class... Fs>
struct overload_t;
// zero
template<>
struct overload_t<> {};
// >1
template <class F0, class... Frest>
struct overload_t<F0, Frest...> :
F0,
overload_t<Frest...>
{
overload_t(F0 f0, Frest... rest) :
F0(std::move(f0)), overload_t<Frest...>(std::move(rest)...)
{}
using F0::operator();
using overload_t<Frest...>::operator();
};
// 1
template <class F0>
struct overload_t<F0> : F0
{
overload_t(F0 f0) : F0(std::move(f0)) {}
using F0::operator();
};
template <class... Fs>
auto overload(Fs... fs)
{
return overload_t<Fs...>(std::move(fs)...);
}
在 C++14 中,它类似于:
template <typename ... Ts> struct overload;
template <typename T>
struct overload<T> : T
{
template <typename U>
overload(U&& u) : T(std::forward<U>(u)) {}
using T::operator();
};
template <typename T, typename ... Ts>
struct overload<T, Ts...> : overload<T>, overload<Ts...>
{
template <typename U, typename ... Us>
overload(U&& arg, Us&&... args) : overload<T>(std::forward<U>(arg)),
overload<Ts...>(std::forward<Us>(args)...) {}
using overload<T>::operator();
using overload<Ts...>::operator();
};
template<class... Ts>
overload<std::decay_t<Ts>...> make_overload(Ts&&... args)
{
return {std::forward<Ts>(args)...};
}