VS c++ compile template with member function pointers with error - c++

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

Related

How do I properly implement "operator()" with "if constexpr" so that it works with std::generate?

I was trying to write a class that will fill a container with random numbers with the type that the container has:
template<typename random_type>
class rand_helper {
private:
std::mt19937 random_engine;
std::uniform_int_distribution<int> int_dist;
std::uniform_real_distribution<double> real_dist;
public:
rand_helper() = delete;
rand_helper(random_type left_b, random_type right_b);
random_type operator()();
};
template<typename random_type>
rand_helper<random_type>::rand_helper(const random_type left_b, const random_type right_b) :random_engine{ std::random_device{}()} {
if constexpr (std::is_same_v<random_type, double>)
real_dist(left_b, right_b );
else
int_dist( left_b, right_b );
}
template<typename random_type>
random_type rand_helper<random_type>::operator()() {
if constexpr (std::is_same_v<random_type, double>)
return real_dist(random_engine);
else
return int_dist(random_engine);
}
But here an error occurs somewhere, because when I call std::generate,then I get a lot of errors:
template<typename T,typename vec_type = typename T::value_type>
void fill_contain(T& container,vec_type left_b=vec_type(0), vec_type right_b= vec_type(100)) {
std::generate(std::begin(container),std::end(container), rand_helper<vec_type>(left_b ,right_b));
}
I thought it might be because of if constexpr but if just leave:
template<typename random_type>
random_type rand_helper<random_type>::operator()() {
return int_dist(random_engine);
}
then the same errors are still returned.
Here is the list of errors I get:
Error C2825 '_Urng': must be a class or namespace when followed by '::'
Error C2510 '_Urng' : left of '::' must be a class / struct / union
Error C2061 syntax error : identifier 'result_type'
Error C2065 '_Ty1' : undeclared identifier
Error C2923 'std::conditional_t' : '_Ty1' is not a valid template type argument for parameter '_Ty2'
The function call goes like this:
std::vector<int> for_sort;
fill_contain(for_sort);
Your code just doesn't compile, regardless of the if constexpr. The reason you may not be getting a compilation error with just the template class is that, well, it's a template, so no actual instance of anything gets compiled. If you add:
template class rand_helper<int>;
which forces an instantiation for a random_type of int, you'll get plenty of compilation error output.
Specifically, you'll be told that you need a pseudo-randomness generator to construct a uniform_int_distribution<int>.
Regardless of the above - you can use something like:
template <typename T>
using uniform_distribution = std::conditional_t<
std::is_integral_v<T>,
std::uniform_int_distribution<T>,
std::uniform_real_distribution<T>
>;
to only have just one distribution member. And in that case, you might not even need your helper class.
To avoid instantiating the std::uniform_real_distribution template class with a non-floating-point type and getting a potentially confusing diagnostic, I'd prefer to use template specializations like this rather than std::conditional_t:
namespace detail
{
template <typename T, typename AlwaysVoid = void>
struct uniform_distribution_impl
{
static_assert(sizeof(T) == 0, "T must be integral or floating point");
};
template <typename T>
struct uniform_distribution_impl<
T, std::enable_if_t<std::is_integral_v<T>>>
{
using type = std::uniform_int_distribution<T>;
};
template <typename T>
struct uniform_distribution_impl<
T, std::enable_if_t<std::is_floating_point_v<T>>>
{
using type = std::uniform_real_distribution<T>;
};
}
template <typename T>
using uniform_distribution = typename detail::uniform_distribution_impl<T>::type;

MSVC:"error C2244: unable to match function definition to an existing declaration" with function refer to type alias of specialized template class

The following code can be compiled with gcc(4.8 and up), while the MSVC (Visual Studio 2017, _MSC_VER 1910) gives error C2244: 'A::func': unable to match function definition to an existing declaration.
#include <iostream>
template<typename T, bool isInt= std::is_integral<T>::value >
class B
{
public:
using RET = T;
};
template <typename T>
class B <T, false>
{
public:
using RET = void;
};
template<typename T>
class A
{
using type = T;
public:
typename B<type>::RET func();
};
template<typename T>
typename B<typename A<T>::type>::RET A<T>::func()
{
std::cout << "func" << std::endl;
return 0;
}
int main()
{
A<int> a;
a.func();
return 0;
}
Full error message from MSVC:
error C2244: 'A<T>::func': unable to match function definition to an existing declaration
note: see declaration of 'A<T>::func'
note: definition
note: 'B<A<T>::type,std::is_integral<T>::value>::RET A<T>::func(void)'
with
[
T=A<T>::type
]
note: existing declarations
note: 'B<T,std::is_integral<_Ty>::value>::RET A<T>::func(void)'
It can compile if I eliminate the template specialization in class B.
template<typename T>
class B
{
public:
using RET = T;
};
It can also compile if I don't use the type alias in class A.
template<typename T>
class A
{
public:
typename B<T>::RET func();
};
template<typename T>
typename B<T>::RET A<T>::func()
{
std::cout << "func" << std::endl;
return 0;
}
And it can also compile if class A is not template.
class A
{
using type = int;
public:
typename B<type>::RET func();
};
It seems that the MSVC does not well support the mix use of template class, type alias and template specialization when separating the class member declaration and definition. I am not sure if there's a special term for this usage. Will the MSVC support this in newer version? Or any existing compile option can fix it?
This issue has been reported to visual studio developer community.
https://developercommunity.visualstudio.com/content/problem/225941/error-c2244-unable-to-match-function-definition-to.html
encountered the same problem today. I guess this is a bug in MVSC. In 15.9 it still exists.

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

How to use a nested template class within a template class from a different template class

First, I hope the question title makes somehow sense.
I have the following class structure:
class A : public Singleton<A>
{
public:
template <typename T> class Buffer
{
public:
//ctor & dtor
T* get() { return ptr; }
private:
T* ptr;
};
// class A stuff
};
This class should be passed to a handler class as template argument and used within the template functions of the class:
template <class MODEL> class Handler
{
public:
// ctor & dtor
template <typename T> typename MODEL::Buffer<T>* create(...) // error c2988
{ // create a buffer }
};
The compiler however is unable to determine the correct typenames and throws error C2988: unrecognizable template declaration/definition (vc++ Nov 2012 CTP compiler within VS 2012). I cannot find any solution to tell the compiler how to handle the innerclass template. So the question is: How to make this work?
Any help would be highly appreciate.
You need to help the compiler to disambiguate and tell it what Buffer is:
template <typename T> typename MODEL::template Buffer<T>* create(...);
// ^^^^^^^^
See this Q&A for more info.

Wrapper for std::queue emplace

I'm working with Visual Studio 2012 on Windows 8 and trying to create a wrapper for std::queue which adds thread safety and a few other features. I'm having trouble creating a wrapper function for emplace. I suspect it's due to the way variadic templates are emulated, but I"m not sure how to fix it.
template <typename T>
class MyQueue
{
public:
template <class... Args> // line 20
void emplace(Args&&... args)
{
mQueue.emplace(std::forward<Args>(args)...);
}
private:
std::queue<T> mQueue;
};
This code gives me a bunch of syntax errors.
# line 20:
C2011: '' : 'enum' type redefinition
C2143: syntax error : missing ',' before '...'
C2332: 'class' : missing tag name
# line 21:
C2059: syntax error : '...'
C2065: 'Args' : undeclared identifier
Is there any clean way to tap into the underlying queue's emplace function? I'm not doing anything performance critical so if it ends up being more trouble than it's worth I'll just force callers to use push.
Any solutions must be with VC++11 - switching platforms or compilers is not an option for me.
I ended up getting this to work by changing the Platform Toolset to the Nov 2012 CTP in the project settings. As others pointed out - the code itself was correct. See below for a simple example.
MyQueue.h:
#pragma once
#include <queue>
template <typename T>
class MyQueue
{
public:
template <class... Args>
void emplace(Args&&... args);
private:
std::queue<T> mQueue;
};
template <typename T>
template <class... Args>
void MyQueue<T>::emplace(Args&&... args)
{
mQueue.emplace(std::forward<Args>(args)...);
}
Main.cpp
#include "MyQueue.h"
struct Test
{
int mA, mB;
Test(int a, int b) : mA(a), mB(b) { }
};
int main()
{
MyQueue<Test> q;
q.emplace(1, 1);
q.emplace(2, 2);
q.emplace(3, 3);
return 0;
}