Template trouble with Visual Studio 2010 - c++

With GCC in Linux, this following code compiles well. But with visual studio, an error C2893 occurs. Do you have any ideas ?
struct A
{
};
struct B
{
typedef A Data;
};
struct C
{
typedef B Data;
};
template<typename Type>
typename Type::Data::Data test( Type in)
{
return Type::Data::Data();
}
int main(){
C c;
C::Data::Data a;//works
test(c);//error C2893: The specialization of the function template 'Type :: Data :: {ctor} test (Type)' failed
}
Thanks a lot
Solution by Avakar: because Data::Data refers to the constructor of the type Data, you have to use this idiom:
typename identity<typename Type::Data>::type::Data

The compiler failed to specialize a function template. There can be many causes for this error. In general, the way to resolve a C2893 error is to review the function's signature and make sure you can instantiate every type.

Related

Why can't Visual C++ partially specialize a class inside a template?

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.

SFINAE std::enable_if fails in visual studio 2015

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!!!

more dependent types with variadic templates

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

VS error referencing class-local typedef as non-inline template argument

The following bit of code (a MWE) compiles in gcc 4.5.3 and above but does not compile in VS 2008 and 2010. Is it a known VS compiler bug? And are there any workarounds, other than to define func() inline.
enum DeviceState{ ON , OFF , BUSY , WAITING };
template<typename T>
struct Foo
{
typedef DeviceState State;
template<State S>
void func(); // no error if implementation is inline
};
template<typename T>
template<typename Foo<T>::State>
void Foo<T>::func()
{
}
int main()
{
Foo<Bar> f;
f.func<ON>();
}
VS error message
error C2244: 'Foo<T>::func' : unable to match function definition to an existing declaration
definition
'void Foo<T>::func(void)'
existing declarations
'void Foo<T>::func(void)'
Edit:
This appears to be another version of an earlier issue I reported.

Need way to determine whether function has void return type in VC6 and VC7

The following C++ code compiles and runs correctly for GNU g++, LLVM and every other C++ compiler I threw at it except for Microsoft VC6 and VC7:
template<typename A, typename B> int HasVoidReturnType(A(*)(B)) { return 0; }
template<typename B> int HasVoidReturnType(void(*)(B)) { return 1; }
void f(double) {}
int foo() { return HasVoidReturnType(f); }
For VC6 and VC7, it fails to compile and gives the error:
f.cpp(4) : error C2667: 'HasVoidReturnType' : none of 2 overloads have a best conversion
f.cpp(2): could be 'int HasVoidReturnType(void (__cdecl *)(B))'
f.cpp(1): or 'int HasVoidReturnType(A (__cdecl *)(B))'
while trying to match the argument list '(overloaded-function)'
f.cpp(4) : error C2668: 'HasVoidReturnType' : ambiguous call to overloaded function
f.cpp(2): could be 'int HasVoidReturnType(void (__cdecl *)(B))'
f.cpp(1): or 'int HasVoidReturnType(A (__cdecl *)(B))'
while trying to match the argument list '(overloaded-function)'
Rather than arguing the merits of what compiler is right, how can I determine from a template function whether a function has a void return type using VC6 and VC7?
As far as VC++ 6 is concerned, you are screwed, as it doesn't support partial template specialisation, which is what you need to solve this problem.
Try this on for size
template<typename FuncPtrType>
struct DecomposeFuncPtr;
template<typename ReturnType, typename ArgType>
struct DecomposeFuncPtr<ReturnType(*)(ArgType)> {
typedef ReturnType return_type;
};
template<typename T>
struct is_void {
enum { value = 0 };
};
template<>
struct is_void<void> {
enum { value = 1 };
};
template<typename T>
int HasVoidReturnType(T dontcare) {
return is_void< typename DecomposeFuncPtr<T>::return_type >::value;
}
it should avoid the overloading that is confusing VC6/7.
Hrmm. Sorry I couldn't test it with VC6/7. I see to recall running into issues using function pointers with templates before in VC though. Since we know the A, B works for the function in your original, I wonder if something like:
template<typename T>
struct is_void {
enum { value = 0 };
};
template<>
struct is_void<void> {
enum { value = 1 };
};
template<typename A, typename B>
int HasVoidReturnType(A(*)(B)) {
return is_void<A>::value;
}
would work.
Instead of creating two templates, have you tried just using the first one and using template specialization to define the second?
FYI this is compilable on C++ 2008 Express edition from Microsoft. (I would have liked to help but can't reproduce the problem on my compiler)