How to Support Variadic Template Types in Visual S

2019-08-23 03:28发布

T.C. gave a clever solution here which used this object:

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&&) {} };

Unfortunately I can't get that to compile in Visual Studio 2017. I get the errors:

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'

Is there any trickery that I can do to make Visual Studio respect the variadic template in?

4条回答
放荡不羁爱自由
2楼-- · 2019-08-23 04:01

You can try to compile in mode with /std::c++17 as @S.M. has noted; note that some C++17 features can break existing code. In addition as @milesbudnek has noted, as of today MSVC doesn't support the requried features.

If you cannot use C++17 mode you can implement this in in this SO answer.

I'd make a few changes:

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)...);
}
查看更多
别忘想泡老子
3楼-- · 2019-08-23 04:05

In C++14, it would be something like:

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)...};
}

Demo

查看更多
放我归山
4楼-- · 2019-08-23 04:11

This is dependent on three separate C++17 features:

  • variadic using-declarations (that support pack expansion)
  • aggregates with base classes
  • class template argument deduction

The usual pre-C++17 workaround for the first is recursive inheritance (forwarding omitted for simplicity):

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...); 
}

The constructors are needed if the compiler doesn't support aggregates with base classes; the make_overload is needed if the compiler doesn't support template argument deduction for class templates.

查看更多
成全新的幸福
5楼-- · 2019-08-23 04:19

It is valid in C++17 only. Try to compile it in Visual Studio 2017 with the flag /std:c++17 under Project -> Properties -> C++ -> Language. Please note, C++17 is available starting from Visual Studio 2017.3.

查看更多
登录 后发表回答