It appears that MSVC 2012 doesn't support using K = ...;-type declarations. For example, with the code:
template <class Map>
inline void foo(Map &m)
{
using K = typename Map::key_type;
using V = typename Map::mapped_type;
// ...
}
The result is a syntax error:
error C2143: syntax error : missing ';' before '='
error C2873: 'K' : symbol cannot be used in a using-declaration
How can I work around this missing feature of MSVC 2012, without upgrading the compiler?
Microsoft's support for C++11 is incomplete, and this is one of the things that's missing in VS2012. But in this case, you should be able to use an old-fashioned typedef; e.g.:
typedef typename Map::key_type K;
The place where this workaround falls apart is when the type is templated:
template<typename T>
using Bar = Foo<T>; // ok if your compiler supports it
template<typename T>
typedef Foo<T> Bar; // doesn't compile
But then you still at least have this option:
template<typename T>
struct Bar
{
typedef Foo<T> type;
};
Related
VS 2005 -> Compilation without any errors.
VS 2010 -> Compilation with any errors.
e.g. code snippet
template< bool f > struct static_assert;
template<> struct static_assert<true> { static_assert() {} };
Compiler Error:
error C2332: 'struct': missing tag name
e.g. code snippet
template< typename T >
class abcd
{
struct xyz
{
xyz();
char c;
T tt;
};
public:
enum { value = sizeof(xyz)-sizeof(T) < sizeof(T) ? sizeof(xyz)-sizeof(T) : sizeof(T) };
};
Compiler Error:
error C2332: 'class': missing tag name
Any suggestions.
In your first code snippet, the problem is that static_assert became a reserved keyword in the C++11 Standard (VS-2010 seems to be using this), whereas it was an 'allowed' identifier in previous versions of the language (such as the VS-2005 compiler was using). To resolve this issue, change the name of your structure, even if that means simply changing the case of one or two letters:
template< bool f > struct Static_Assert; // C++ is case-sensitive, so this is OK!
template<> struct Static_Assert<true> { Static_Assert() { } };
I cannot reproduce the issue in your second code snippet (using VS-2010).
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.
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 ;)
When I try to run this code in Visual C++ (2015)
template<int V>
struct outer
{
template<int U, bool>
struct inner;
};
template<int V>
template<bool B>
struct outer<V>::inner<V, B> { enum { value = 0 }; };
int main()
{
return outer<1>::inner<1, false>::value;
}
I get the error
Temp.cpp(13): error C2027: use of undefined type 'outer<1>::inner<1,false>'
Temp.cpp(13): note: see declaration of 'outer<1>::inner<1,false>'
Temp.cpp(13): error C2065: 'value': undeclared identifier
However, it compiles and runs fine on GCC and Clang.
Three questions:
If the partial specialization isn't partially specializing, what is it doing?
Why does this happen? Is it a bug, or is there really a problem with this code?
Is there a workaround that lets you still use the inner template class inside the inner template class, or is the only solution to move the template arguments outside?
This is a known limitation in the implementation of C++ in Visual C++ 2015 (one of many).
This does work in Visual C++ 2017, so a version upgrade may be necessary.
I was trying to port an open sourced project from linux to window, there are some code that compiles perfectly in linux using either g++ or clang++, but I cannot compile it under MSVC 2015, could anyone tell me how to fix it or how to get around it? I appreciate very much for your help!!!
Here is the code (I have simplified it so you can focus on the key stuff)
template <typename T, class IsMatch = void>
class vc_hashkey
{
public:
static constexpr bool holds_value() { return false; }
};
template <typename T>
class vc_hashkey<T, typename std::enable_if<std::is_integral<T>::value>::type>
{
public:
static constexpr bool holds_value() { return true; }
};
template <typename T, class IsMatch = void>
class vc_hashkey_and_value
{
};
template <typename T>
class vc_hashkey_and_value<T, typename std::enable_if<vc_hashkey<T>::holds_value()>::type>
{
};
That's it, I did not even used these code pieces in my main function. When I tried to compile, the msvc 2015 update RC1 compiler gives me compile errors on the partial specialization of the class vc_hashkey_and_value, saying:
C2039 'type': is not a member of 'std::enable_if<'false, void>'
C2146 syntax error: missing '>' before identifier 'type'
C2064 term does not evaluate to a function taking 0 arguments
Is this a MSVC compiler error, thanks for helping me!!!
The following MWE compiles on gcc 4.8.2 but not on MSVC 2008 (company policy)
struct B
{
};
struct A
{
typedef B Handler;
};
template<typename T>
struct Foo
{
typedef typename T::Handler Type;
};
template<typename T>
struct Bar
{
friend struct Foo<T>::Type; // MSVC 2008 does not like this
typedef typename Foo<T>::Type Foo;
};
int main()
{
}
MSVC 2008 error
error C2649: 'Foo<T>::Type' : is not a 'struct'
Is this a compiler bug or am I doing something illegal here? More importantly is there a fix?
Remove the struct keyword and replace it with typename:
template<typename T>
struct Bar
{
friend typename Foo<T>::Type;
typedef typename Foo<T>::Type Foo;
};
It seems to be invalid. [class.friend]/3:
A friend declaration that does not declare a function shall have one
of the following forms: friend
elaborated-type-specifier; friend simple-type-specifier; friend typename-specifier;
However, there is an important restriction on elaborated-type-specifiers: [dcl.type.elab]/2:
If the identifier resolves to a typedef-name […] the
elaborated-type-specifier is ill-formed.
In that respect, GCC and Clang are wrong and, surprisingly, VC++ is right.
You can make use of the third bullet of the first quote and use a typename-specifier.
friend typename Foo<T>::Type;