C++/CLI Compilation error with generic delegate - compilation

I'm currently doing some work with C++/CLI, and am encountering a strange compilation error with the following code:
private ref class LinqHelper abstract sealed
{
public:
generic<typename T, typename U> static Func<T, U>^ Cast()
{
return gcnew Func<T, U>(&LinqHelper::Cast);
}
private:
generic<typename T, typename U> static U Cast(T val)
{
return safe_cast<U>(val);
}
};
error C3352: 'Cast' : the specified function does not match the delegate type 'U (T)'
To be more specific, the problematic line of code is:
return gcnew Func<T, U>(&LinqHelper::Cast);
I find myself at a loss to explain this error. The Cast static member function that I am passing to the Func delegate constructor has the required signature, i.e. U Cast(T val).
Could anyone help shed some light on this for me please?
If it is of any help: i am working with VS 2015 and the C++/CLI project is referencing the .NET framework v4.5.2.
Thank you

The compiler is not happy about having to infer the type arguments for the Cast method. Lousy error message, not uncommon in C++/CLI. Fix:
return gcnew Func<T, U>(&LinqHelper::Cast<T, U>);

Related

C++11 Call virtual member function

I`m trying to implement something like this using C++11.
class Proto{
public:
virtual void fu() = 0;
};
class Impl: public Proto{
public:
void fu();
};
void Impl::fu(){
LOG_INFO("im fu");
}
class Inv{
public:
void useFu(void (Proto::*)());
};
void Inv::useFu(void (Proto::*fu)()){
//fu();
};
void main(){
Impl impl;
Inv inv;
//inv.useFu(impl.fu);
}
useFu(void (Proto::*)()) must be declared in this way because, fu() uses some specific to Proto functionality's
I have two places were things going wrong.
First is fu() call itself and second how to pass fu as parameter inv.useFu(impl.fu).
Edit after bipll answer
The suggested usage of inv.useFu() solves the second problem of my question.
inv.useFu(static_cast<void (Proto::*)(void)>(&Impl::fu));
But I still need to call fu as a pointer to member function;
The way your useFu is declared now, it should be called as
inv.useFu(static_cast<void (Proto::*)(void)>(&Impl::fu));
But I guess that's not what you wanted. It should rather be
template<class F> void useFu(F &&f) { std::invoke(std::forward<F>(f)); }
or simply
void useFu(std::function<void()> f) { std::invoke(std::move(f)); }
and called as
useFu([&]{ impl.fu(); });
(Rather than using a lambda you can bind the method to the object with std::bind in the latter call but almost nobody ever does that.)

Inferencing the typename of 'this' in a virtual method

I am aware of the lack of reflection and basic template mechanics in C++ so the example below can't work. But maybe there's a hack to achieve the intended purpose in another way?
template <typename OwnerClass>
struct Template
{
OwnerClass *owner;
};
struct Base
{
virtual void funct ()
{
Template <decltype(*this)> temp;
// ...
}
};
struct Derived : public Base
{
void whatever ()
{
// supposed to infer this class and use Template<Derived>
// any chance some macro or constexpr magic could help?
funct();
}
};
In the example, Derived::whatever() calls virtual method Base::funct() and wants it to pass its own class name (Derived) to a template. The compiler complains "'owner' declared as a pointer to a reference of type 'Base &'". Not only does decltype(*this) not provide a typename but a reference, the compiler also can't know in advance that funct is called from Derived, which would require funct() to be made a template.
If funct() was a template however, each derived class needs to pass its own name with every call, which is pretty verbose and redundant.
Is there any hack to get around this limitation and make calls to funct() infer the typename of the calling class? Maybe constexpr or macros to help the compiler infer the correct type and reduce verbosity in derived classes?
You should use CRTP Pattern (Curiously Recurring Template Pattern) for inheritance.
Define a base class:
struct CBase {
virtual ~CBase() {}
virtual void function() = 0;
};
Define a prepared to CRTP class:
template<typename T>
struct CBaseCrtp : public CBase {
virtual ~CBaseCrtp() {}
void function() override {
using DerivedType = T;
//do stuff
}
};
Inherit from the CRTP one:
struct Derived : public CBaseCrtp<Derived> {
};
It should work. The only way to know the Derived type is to give it to the base!
Currently, this can't be done. Base is a Base and nothing else at the time Template <decltype(*this)> is instantiated. You are trying to mix the static type system for an inheritance hierarchy inherently not resolved before runtime. This very same mechanism is the reason for not calling virtual member functions of an object during its construction.
At some point, this limitation might change in the future. One step towards this is demonstrated in the Deducing this proposal.

Error during template substitution reported by compiler

I'm seeing a build error which is correct, but something that I would expect to be ignored due to the Substitution Failure Is Not An Error rule:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(895): error C3699: '&&': cannot use this indirection on type 'System::String ^'
RemoteWrapper.cpp(41): note: see reference to class template instantiation 'std::vector<System::String ^,std::allocator<_Ty>>' being compiled
with
[
_Ty=System::String ^
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(918): error C3699: '&&': cannot use this indirection on type 'System::String ^'
Here's the code which the error mentions:
std::string nativeString;
String^ clrString = clr_cast<String^>(nativeString);
Here are the clr_cast templates:
template<typename TReturn, typename TSource>
TReturn clr_cast(TSource value)
{
return (TReturn)value;
}
template<typename TReturn, typename TSource, typename = std::enable_if<!std::is_same<TReturn, TSource>>::value>
std::vector<TReturn> clr_cast(array<TSource>^ value)
{
[iterate and cast]
}
template<typename T>
std::vector<T> clr_cast(array<T>^ value)
{
[memcpy]
}
template<typename TReturn, typename TSource, typename = std::enable_if<!std::is_same<TReturn, TSource>>::value>
array<TReturn>^ clr_cast(std::vector<TSource> value)
{
[iterate and cast]
}
template<typename T>
array<T>^ clr_cast(std::vector<T> value) // this is the problematic function
{
[memcpy]
}
template<> std::string clr_cast(System::String^ value);
template<> System::String^ clr_cast(std::string value);
The compiler is trying to instantiate the function to which I added a comment and it's correct that it fails to do so. What I don't understand is that if I remove it then the compiler will select the correct function (the specialisation right at the end of the header) and continue happily onward.
It seems to me that the error I'm seeing is occurring during substitution, and that the compiler should therefore silently discard the std::vector<T> candidate and fall back on the specialisation. Why is this not happening?
This was happening because SFINAE only applies to the "immediate context", i.e. the template parameter itself.
The error can be turned into a substitution failure by moving the problematic instantiation into the template parameters, like this:
template<typename T, typename = T&&>
array<T>^ clr_cast(std::vector<T> value)
function
{
[memcpy]
}
The code now compiles successfully, and the appropriate clr_cast overload is selected.

What's the right way to call static_assert(false)?

I’m trying to use static_assert to force something to fail. If you try to instantiate a specific templated function in a specific way I want to generate a complier error. I could make it work, but it was really ugly. Is there an easier way to do this?
This was my first attempt. This did not work at all. It always generates an error, even if no one tries to use this function.
template< class T >
void marshal(std::string name, T *value)
{
static_assert(false, "You cannot marshal a pointer.");
}
Here’s my second attempt. It actually works. If you don’t call this, you get no error. If you do call this, you get a very readable error message that points to this line and points to the code that tried to instantiate it.
template< class T >
void marshal(std::string name, T *value)
{
static_assert(std::is_pod<T>::value && !std::is_pod<T>::value, "You cannot marshal a pointer.");
}
The problem is that this code is ugly at best. It looks like a hack. I’m afraid the next time I change the optimization level, upgrade my compiler, sneeze, etc, the compiler will realize that this second case is the same as the first, and they will both stop working.
Is there a better way to do what I’m trying to do?
Here’s some context. I want to have several different versions of marshal() which work for different input types. I want one version that uses a template as the default case. I want another one that specifically disallows any pointers except char *.
void marshal(std::string name, std::string)
{
std::cout<<name<<" is a std::string type."<<std::endl;
}
void marshal(std::string name, char *string)
{
marshal(name, std::string(string));
}
void marshal(std::string name, char const *string)
{
marshal(name, std::string(string));
}
template< class T >
void marshal(std::string name, T value)
{
typedef typename std::enable_if<std::is_pod<T>::value>::type OnlyAllowPOD;
std::cout<<name<<" is a POD type."<<std::endl;
}
template< class T >
void marshal(std::string name, T *value)
{
static_assert(false, "You cannot marshal a pointer.");
}
int main (int argc, char **argv)
{
marshal(“should be pod”, argc);
marshal(“should fail to compile”, argv);
marshal(“should fail to compile”, &argc);
marshal(“should be std::string”, argv[0]);
}
There is no way to do this. You might be able to make it work on your compiler, but the resulting program is ill formed no diagnostic required.
Use =delete.
template< class T >
void marshal(std::string name, T *value) = delete;
What you are trying to do is doomed to be ill-formed (even your workaround can fail) according to [temp.res]/8 (emphasis mine):
Knowing which names are type names allows the syntax of every template
to be checked. The program is ill-formed, no diagnostic required, if:
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the
template is not instantiated, or (...)
Relying on a contradiction is not the best indeed, but there's a simpler way:
template <class...>
struct False : std::bool_constant<false> { };
template <class T>
void bang() {
static_assert(False<T>{}, "bang!");
}
Why does this not fall under the "no valid specialization" case?
Well, because you can actually make a valid specialization, with that second half of the code:
template <>
struct False<int> : std::bool_constant<true> { };
int main() {
bang<int>(); // No "bang"!
}
Of course, no one is actually going to specialize False to break your assertions in real code, but it is possible :)
I don't understand why you have template< class T > void marshal(std::string name, T *value) in the first place. This should just be a static_assert in the primary template.
That is, you should change the definition of your primary template to
template< class T >
void marshal(std::string name, T value)
{
static_assert(std::is_pod<T>::value);
static_assert(!std::is_pointer<T>::value);
std::cout<<name<<" is a POD type."<<std::endl;
}

How to elegantly restrict a template argument to be a `<Certain_Class<AnyT>>`?

How to restrict a template argument of Wrapper to be a Wrapper<Any,MyArray<AnyT>> elegantly?
Don't break content assist (Visual Studio).
High readability. Not use a hacky approach.
For some reasons, most solution love to hack.
Make it obvious at the very first line by using C++ syntax rule. (not just green comment)
As far as I know, there are many solutions, but every solution doesn't meet the criteria.
Workaround 1 (template specialization, fail 1)
template<class T> class MyArray{};
template<class T,class T2> class Wrapper;
template<class T,class T2> class Wrapper<T,MyArray<T2>>{
using Test=int;
};
class B{};
class C{};
int main() {
Wrapper<C,MyArray<B>> wrapper;
return 0;
}
This code is modified from https://stackoverflow.com/a/43518221 (#max66).
Context clue / syntax highlighting of IDE will be confused.
In my case, it marks some correct types as error e.g. :-
class ShowError : public Wrapper<B,MyArray<C>>{
Test n=0; //<-- unknown "Test" (intellisense)
};
Workaround 2 (some hacky field/typedef, fail 2)
template<class T> class MyArray{
public: using MyArrayT=T;
};
template<class T,class T2> class Wrapper{
public: using myT=typename T2::MyArrayT;
//^ assert at compile time
};
This idea come from a comment in https://stackoverflow.com/a/43518295 (#Jarod42)
The class declaration doesn't mention about MyArray, it just uses a hacky (less readable) way (MyArrayT) to enforce that T2 is MyArray.
Workaround 3 (base class, fail 2)
class MyArrayBase{};
template<class T> class MyArray : public MyArrayBase{ };
template<class T,class T2> class Wrapper{
//check something around MyArrayBase *object = new T2();
// or "is_base_of"
};
The code is modified from Restrict C++ Template Parameter to Subclass and C++ templates that accept only certain types.
It has same disadvantage as workaround 2.
It is not obvious for common user.
Workaround 4 (SNIFAE, fail 1)
By adding std::enable_if on the template class declaration (Wrapper), I can get a working hack.
Unfortunately, content assist hate it.
Reference
Here are the other links that I read :-
http://www.informit.com/articles/article.aspx?p=376878 (template template parameter)
restrict a template function, to only allow certain types (not related to template type as a parameter)
You can write a custom type trait is_specialization, as follows:
template<class Type, template<class...> class Template>
struct is_specialization
: std::false_type {};
template<template<class...> class Template, class... TArgs>
struct is_specialization<Template<TArgs...>, Template>
: std::true_type {};
Then you just need to static_assert that is_specialization is true for the given template argument:
template<class T,class T2>
class Wrapper {
static_assert(is_specialization<T2, MyArray>::value, "T2 must be a specialization of MyArray");
};

Resources