msvc function traits on lambda - c++11

I'm trying to use the function traits that was posted as the marked answer here:
Is it possible to figure out the parameter type and return type of a lambda?
While trying to compile it with msvc 19.16.27034 I get the following errors:
Error C2825 'T': must be a class or namespace when followed by '::'
Error C2510 'T': left of '::' must be a class/struct/union
Error C2065 '()': undeclared identifier
Error C2955 'function_traits': use of class template requires template argument list
On godbolt this works on any compiler but for some reason on my local machine I can't get this to compile because of these errors. Am I missing something?
UPDATE:
Adding std::remove_reference_t
template <typename T>
struct function_traits
: public function_traits<decltype(&std::remove_reference_t<T>::operator())>
{
};
to the declaration solves the problem.
The weird part is that even without any instantiation to the template I still get this error on the specified compiler, unless I'm adding std::remove_reference_t.
Anyone can explain this weird behaviour?

Related

Friend alias template does not compile with clang

The code bellow compiles without a warning on GCC and issues an error with clang (any c++11 compatible versions of both clang and GCC).
Which compiler is right with respect to the standard?
Specifically, is it allowed to declare as friend a non partially specialized template alias which is a partial template specialization of a class?
This makes me think that it might not be allowed:
cppreference says: "Friend declarations cannot refer to partial specializations [...]".
And also: "A type alias declaration introduces a name which can be used as a synonym for the type denoted by type-id. It does not introduce a new type [...]".
Finally: "Both function template and class template declarations may appear with the friend specifier [...]". It implicitly excludes the possibility for a template alias to be a friend of a class as an actual template alias but rather as the aliased class template, which is a partial specialization in the snippet bellow.
However, this makes me think that it might be allowed:
cppreference says : "An alias template is a template [...]". I undestand that a template alias is a distinct template. By consequence, declaring it as friend as in the following example without partial specilization of the class template alias is valid... Or not.
This code (not from me) also gives a workaround and let me think that there is no obvious reason for making the following code ill-formed.
This post asks a very similar question but no clear answer was provided with respect to the specific usage of an intermediate template alias.
template<typename T,typename N> class B{};
template<typename T> class A{
// template<typename U> friend class B<T,U>; fails as expected
template<typename N> using alias = B<T,N>;
template<typename N> friend class alias;
};
Intent: legal way to declare a partial specialization as friend using an intermediate alias (workaround).
Result: GCC is happy with it and produces the intended behaviour. Clang produces the following error:
<source>:7:35: error: redefinition of 'alias' as different kind of symbol
template<typename N> friend class alias;
^
<source>:6:22: note: previous definition is here
template<typename N> using alias = B<T,N>;

How to pass unique_ptr object as argument to a class that is a library

I read all the questions and answers related to passing unique_ptr as argument to a class constructor and those answers worked for classes within the exe. But here im trying to pass an unique_ptr object to a class constructor that is pre-compiled as static library.
This class in the library looks something like this,
// Class declaration (in a header file)
class TScreen
{
private:
std::unique_ptr<TProcess> m_process;
public:
__fastcall TScreen(int a, std::unique_ptr<TProcess> i_process);
};
// The constructor definition (in a separate .cpp file)
__fastcall TScreen::TScreen(int a, std::unique_ptr<TProcess> i_process):
m_process(std::move(i_process))
{
}
I will be trying to instantiate the class TScreen in the exe like this,
void TScreen_Main::CallScreen()
{
std::unique_ptr<TProcess> objprocess (new TProcess());
std::unique_ptr<TScreen> objscreen (new TScreen(0, std::move(objprocess)));
}
I compiled the library and imported it to the exe. When i compile the exe, it gives me a link error like this,
[ilink32 Error] Error: Unresolved external '__fastcall TScreen::TScreen(int, std::unique_ptr<TProcess, std::default_delete<TProcess> >)' referenced from TSCREEN_MAIN.OBJ
[ilink32 Error] Error: Unable to perform link
I tried the same with boost::shared_ptr as well and it gives me the same error. But it works fine with raw pointers, but not with smart pointers and i cannot figure out why?
Thanks in advance.
Your problem here is a linking issue. Now, exactly what's going on is difficult for me to say because I never work in a Windows environment, and linking is something that (while very similar) has some distinct differences between a Unix/Linux and a Windows environment.
My guess is that if you explicitly declare your constructor to be inline, and declare that the definition is inline, it will work correctly.
This presumes that the fact that you put the declaration of the class and definition together indicates that the definition is in the header file with the class.
When the compiler sees that it's declared inline it will emit a definition into every compilation unit where it's needed. The linker should then eliminate all the duplicate definitions.
If you really are defining the constructor in some .cpp file separate from the .hpp file that the class is in, and you compiler that .cpp file into .obj file that eventually makes it into a .lib or .dll that you link against when creating the executable, then I don't know what the problem is. If this is the case, you should use the tools that should come with your development environment to see what symbols are actually in the library or the dll because somehow the symbol for the constructor definition isn't there.

Is it valid to return a unique_ptr pointing to a forward declared class?

Following code does not compile with clang-700.1.81 and it's standard library:
#include <memory>
class something;
std::unique_ptr<something> external_function();
std::unique_ptr<something> local_function()
{
auto thing = external_function();
return thing;
}
The diagnostics by clang:
......./include/c++/v1/memory:2626:46: note: in instantiation of member function 'std::__1::unique_ptr.....requested here
_LIBCPP_INLINE_VISIBILITY ~unique_ptr() {reset();}
^
test.cc:10:18: note: in instantiation of member function 'std::__1::unique_ptr<something, std::__1::default_delete<something> >::~unique_ptr' requested here
auto thing = external_function();
^
test.cc:4:7: note: forward declaration of 'something'
class something;
^
I guess it is trying to destroy the unique_ptr after copying it as return value, but is this really necessary? It is going be moved anyways, does it need to check if it can copy before realizing that it is easier to move it?
I could of course do this easily with a naked pointer.
Is there some other way to allow a uniqe_ptr to just "pass through" a translation unit, as shown in the example, without including extra header to get the definition of class something?
------EDIT--------
Also tried with GCC 5.3.0 and gnu libstdc++
Does not compile as well, with similar error messages.
------EDIT----
I think it is just trying to destroy the original thing object.
Thanks to Rudolf for the deleter idea ( a bit messy, but only option for this )
Looking at the library code I found this in unique_ptr's code:
if (__tmp)
__ptr_.second()(__tmp);
where second(_tmp) destructs the object pointed to. Even though it is never called, the compiler needs a definition to compile it. This is silly, but apparently gotta live with it.
From cppreference.com:
std::unique_ptr may be constructed for an incomplete type T, such as to facilitate the use as a handle in the Pimpl idiom. If the default deleter is used, T must be complete at the point in code where the deleter is invoked, which happens in the destructor, move assignment operator, and reset member function of std::unique_ptr. (Conversely, std::shared_ptr can't be constructed from a raw pointer to incomplete type, but can be destroyed where T is incomplete).
Thus, with a custom deleter you can use a forward declared class if the full declaration is available for the deleter:
#include <memory>
class Foo;
class FooDeleter
{
public:
void operator()(Foo* pInstance);
};
std::unique_ptr<Foo, FooDeleter> pFoo;
class Foo
{
};
void FooDeleter::operator()(Foo* pInstance)
{
delete pInstance;
}

Calling a property on the const reference

I have C++/CLI class that defines a property:
public ref class AbstractOffer
{
public:
AbstractOffer();
property String^ Body;
};
In some function the AbstractOffer class is passed by const ref
foo(const AbstractOffer^ ao)
{
ao->Body;
}
When I call the property the method compiler gives the following error :-
error C2662: 'ivrworx::interop::AbstractOffer::Body::get' : cannot
convert 'this' pointer from 'const ivrworx::interop::AbstractOffer'
to 'ivrworx::interop::AbstractOffer %' 1> Conversion loses
qualifiers
It seems somehow connected to const. How can I call the Body property of the object if the object reference is passed by const?
The const qualifier is a problem in C++/CLI. It is only meaningful when it can be checked and that's not in general possible in .NET. It is of course not a problem when you only have one kind of compiler and that compiler follows strict language rules. Like C++. But .NET supports many languages, your method could be easily called from a Cobol.NET program for example. The odds of ever getting const-correctness added to the Cobol language are zero.
The compiler does compile code with const qualifiers and does make an effort to check when it can. Which is why you got the diagnostic. That can even work when the declaration exists in another assembly, as long as it was compiled with C++/CLI, the compiler emits modopt annotations in the metadata.
But there are limitations with that. Properties are one of them, you can't add the const qualifier to the getter, or a member function in general, you'll get slapped with C3842.
Best thing to do is to use C++/CLI for what it is good at, it is an interop language. And const qualifiers just don't work well in an interop scenario.
The only way I know to get round this is the cast away the const-ness. As long as you don't modify the object, it should be fine. (If you do modify it, I've no idea what the outcome will be).
i.e. change your function to be
void foo(const AbstractOffer^ ao)
{
const_cast<AbstractOffer^>(ao)->Body;
}

C++/CLI: Public ref struct generates C2011: 'class' type redefinition

I have a header file in a managed DLL project like so:
Enums.h:
#pragma once
...
public ref struct ManagedStruct {
Bitmap^ image;
}
...
This header is referenced both from another class in the DLL and from a separate executable. The managed struct alone is generating:
error C2011: 'ManagedStruct' : 'class' type redefinition.
If I move the struct to the main header file in the DLL it works fine, and is publicly accessible, so that's what I'm doing, but I would very much like to learn why this is happening when I just move it to another file.
I have checked all necessary includes and namespaces AND tried the obvious header guards, to no avail; I still get the error.
Thanks very much for any insight!
You have to de-tune the traditional C/C++ header file think a bit when you work with managed code. The principal source of type declarations is the assembly metadata. This is very different from the native C/C++ compilation model where you have to have a header file for types that you make visible to other modules.
I'm going to guess that you get this C2011 error in the EXE project. Where you both added a reference to the DLL project assembly (like you should) and used #include on the header file. Like you should not. That's a guaranteed duplicate definition, #pragma once doesn't fix that.
Don't use header files for exported type definitions. Always use assembly references.
I Know this question is a bit old, but I'm writing this for future usage:
I had the following problem, which was similar:
managed DLL had a managed class.
managed.h:
namespace Managed {
ref class CManagedClass {...}
}
in an unamanged class I wanted to use this above class and so in unmanaged.h
#include "managed.h"
in another DLL I also did:
#include "unmanged.h"
which resolved in the type redefinition error.
I have found a solution to this issue using the following method:
forward declaration in the unmanaged.h
namespace Managed {
ref class CManagedClass;
}
and include the managed.h in the unmanaged.cpp file as usual.

Resources