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!!!
Related
The code like this:
template<class hostClassType, typename returnType, typename ...argumentType>
class Delegate
{
public:
typedef returnType (hostClassType::*ClassFunctionType)(argumentType...);
Delegate(hostClassType* obj, ClassFunctionType func)
{
m_HostObject = obj;
m_ClassFunction = func;
}
private:
hostClassType* m_HostObject;
ClassFunctionType m_ClassFunction;
}
Visual Studio 2019 compile it with error:
Error C2825: 'hostClassType': must be a class or namespace when followed by '::'
Tried with <typename hostClassType> and <class hostClassType> in the template. none of them works. Does anyone know what is the problem with the code?
Thank you very much
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 get what appears to be a Visual Studio bug when I compile time test if a type with a default template parameter has some property. In the minimal example below I use std::is_integer.
When compiling the following program with Visual Studio 2017
#include <type_traits>
#include <utility>
#include <algorithm>
template<typename U,
typename Enabled = typename std::enable_if<std::is_integral<U>::value>::type>
struct wrapper
{
};
template<typename U, typename storage_type>
using is_small = std::is_void<typename std::enable_if <
(sizeof(wrapper<U, char>) <= sizeof(storage_type))
>::type>;
I get the following output
1>bug.cpp(13): error C2027: use of undefined type 'wrapper<U,char>'
1>bug.cpp(13): note: see declaration of 'wrapper<U,char>'
The same program does compile on g++ 6.1.
The program does compile on Visual Studio when the default parameter Enable is removed. In addition, when I perform the same sizeof(...)<=sizeof(...) test in the following template member function the program compiles fine (with is_small removed).
struct c
{
template<typename U, typename storage_type>
typename std::enable_if<(sizeof(wrapper<U, char>) <= sizeof(storage_type))>::value
foo(U u, storage_type t)
{}
};
Somehow the issue is related to the definition of is_small.
Does anyone know what the issue is? Is it a Visual Studio bug? Is there a workaround?
Edit
Reduced version:
template<class, class> struct A { };
template<int> struct B { };
template<class T> constexpr auto x = sizeof(A<T, int>); // works
template<class T> struct C : B<sizeof(A<T, int>)> { }; // works
template<class T> using D = B<sizeof(A<T, int>)>; // doesn't work
A possible workaround could be to use x instead of is_small.
Bug report submitted: https://developercommunity.visualstudio.com/content/problem/204504/issues-with-sizeof-alias-templates-and-virtual-fun.html
The test program compiles with VS2015 but not with VS2017 RC. Below is the error I am getting while compiling the test program with VS2017 RC:
/* main.cpp */
#include <type_traits>
template <typename T>
struct A_impl
{
using type = std::false_type;
};
template <typename T>
using A = typename A_impl<T>::type;
template <bool... B>
struct logic_helper;
template <bool... B>
using none_t = std::is_same<logic_helper<B...>, logic_helper<(B && false)...>>;
template <typename... C>
struct Foo
{
// Compile error:
// error C3520: 'C': parameter pack must be expanded in this context
using FooType = none_t<A<C>::value...>;
};
int main()
{
Foo<int, int, int> foo;
return 0;
}
I would like to know why the newest Visual Studio fails to compile the code while the older version has no problem with it. If possible, is there a solution to this compile error for VS2017 RC?
I found a workaround to the problem, but I still can't understand why the compiler complains with my first approach:
template <typename... C>
struct Foo
{
// Workaround
using FooType2 = logic_helper<A<C>::value...>;
using FooType3 = logic_helper<(A<C>::value && false)...>;
using FooType4 = std::is_same<FooType2, FooType3>;
};
This follows yesterday's question, where I gave some C++ code that Visual Studio 2013 couldn't handle, and #galop1n kindly provided a workaround, which worked perfectly for that case. But now I've gone a tiny bit further and Visual Studio is giving me grief again.
template <typename T>
using ValueType = typename T::value_type;
template<typename... Containers>
void
foo(const Containers &...args) {
std::tuple<ValueType<Containers>...> x;
}
template<typename... Containers>
struct Foo {
std::tuple<ValueType<Containers>...> x;
};
Whenever I try to instantiate either function template foo or class template Foo, I get these two messages:
Test.cpp(21): error C3546: '...' : there are no parameter packs available to expand
and
Test.cpp(21): error C3203: 'ValueType' : unspecialized alias template can't be used as a template argument for template parameter '_Types', expected a real type
In each case (instantiating foo or instantiating Foo), both messages point to the line that defines "x".
UPDATE: My Microsoft bug report now has (in its attachment) all the basic variants of this problem. So that would be the place to watch for a fix.
Maybe following works on VS2013 (more verbose :/ ):
template<typename... Containers>
void foo(const Containers &...args) {
std::tuple<typename std::decay<decltype(*args.begin())>::type...> x;
}
template<typename... Containers>
struct Foo {
std::tuple<typename std::decay<decltype(*std::declval<Containers>().begin())>::type...> x;
};