Search code examples
c++visual-c++decltypedeclval

How to use decltype as the LHS of a larger type expression when compiling under VS2010-VS2015


I've got two versions of code both using decltype and declval. One works and one doesn't. They are included below. I've tested this on VS2017 and below and I get the same results. VS2018 will compile it. GCC and Clang both compile it all.

The error that is generated for the failing case under MSVC is

[x86-64 MSVC 19 2017 RTW #1] error C3646: 'type': unknown override specifier

for the line

typedef typename decltype(boost::declval<Func>()(SegmentVec()))::value_type type;

See God Bolt for a live version of the below code.

#include <vector>
#include "boost/type_traits/declval.hpp"

typedef std::vector<int> SegmentVec;

/////////////////////////////////
// The below fails
template <typename Func> struct Traits {
    typedef typename decltype(boost::declval<Func>()(SegmentVec()))::value_type type;
};
template <typename F> auto Hof(F f) -> typename Traits<F>::type {
    return f(std::vector<int>{2})[0];
}
/////////////////////////////////


/////////////////////////////////
// The below works
template <typename Func> struct Traits2 {
    typedef typename decltype(boost::declval<Func>()(SegmentVec())) type;
};
template <typename F> auto Hof2(F f) -> typename Traits2<F>::type {
    return f(std::vector<int>{2});
}
/////////////////////////////////


int main(){
    auto lmd = [](std::vector<int> const & a){return a;}; 

    Hof(lmd);
    Hof2(lmd);
}

Is it possible to get the code to compile under MSVC 2010 upwards without significantly changing the code. The code in itself above is an extraction from a larger body of code and doesn't necessarily have any meaning apart from demonstrating the compiler error.


Solution

  • To please that buggy MSVC, you can do it in part (demo):

    template <typename Func> struct Traits {
        typedef decltype(boost::declval<Func>()(SegmentVec())) suptype;
        typedef typename suptype::value_type type;
    };
    

    using Tnew = Told; is a better syntax though ;)