I have non-template class on C++ side is it possible to extend it with template method? So far it didn't work for me.
I've tried
%extend A {
template <typename T>
void fn(T t) {
// some common code
}
}
%template (Afni) A::fn<int>;
...;
But A::fn<int> not generated for me in such way in cxx file.
So I have to use
%extend A {
void fn(int t) {
// some common code
}
...
}
drawback of such approach is duplication of the same common code.
SWIG must know how to translate templated types. Every type not translated by default should be defined for SWIG with %typemap. Concerning %extend, it should work like the following:
//This is for compiling cxx as an ordinary cpp
%header %{
#include "class_header.h"
}
//OriginalClass is defined in the "class_header.h".
//So, it is already known to SWIG but not declared as the destination class.
//Here is the class definition for the destination code.
//All members defined in it supported by SWIG with the appropriate proxying code.
class OriginalClass {
//Here you may declare all the members you want to access in the destination code
inline const some_internal_type & get_data() const;
//some_internal_type is assumed known to SWIG after declaring it with %typemap for in/out converting
//Here is the whole block extending OriginalClass
%extend {
template<class T>
void fn(T t) {
}
void setup(other_data p_dest) {
//There is no the setup member in OriginalClass, but this method is available for the destination code
//other_data is typemapped somewhere above for SWIG using %typemap
}
}
};
For each substituted T into fn SWIG should be provided with proper %typemap for representing that T in the proxying code.
Related
I am having a problem with the changes that were made to the way C++ templates are compiled, between the C++17 and 19 standards. Code that used to compile in VS2017 throws a compiler error since I upgraded to VS2019 or VS2022.
Situations have to do with the fact that the compiler now runs a basic syntax check on the template definition when it sees this definition ("first pass") and not only when the template is actually used.
Code example 1:
class Finder
{
template<typename T>
T convert_to(HANDLE h)
{
return Converters::Converter<T>::Convert(get_data(h));
}
};
Here, the template class Converter<> resides in namespace Converters, and get_data is a member function of Finder which returns something that can be passed into the Convert function.
Since we're dealing with templates, this code sits in a header file "Finder.h". The header file doesn't #include "Converters.h". Finder.h is shared across several projects, some of which don't even know the Converters.h file namespace.
As long as no code calls the MyClass::convert_to<> function, this compiles in VS2017, but not so in VS2019 and VS2022:
error C3861: 'Converters': identifier not found
The obvious solution is, of course, to #include "Converters.h" either in this header file, or in the precompiled headers file. However, as was said, Converters.h is not known in all places which use MyClass. Another solution would be to use archaic #define CONVERTERS_H in the Converters.h header and enclose the function definition in #ifdef CONVERTERS_H, but this looks really ugly.
My question is: Is there a way to prevent the compiler from doing this "first pass"? Or to re-write this code so that it compiles? I don't mind if it's MS specific; no other compiler will ever see the code.
Code example 2:
class MyClass2
{
template<class T>
static void DoSomething(T* ptr) { static_assert(false, "Don't do this"); }
// lots more member functions, most of them 'static'
};
template<> void MyClass::DoSomething(CWnd* ptr) { /*some useful code*/ }
/// and some more specializations of DoSomething
The intention is that the static_assert should emit an error message whenever DoSomething is called with an argument for which no explicit specialization of this template function is defined. This worked in VS2017, but in VS2022, the "first pass" of the compiler triggers the static_assert.
Again, I wonder how I could achieve this effect, other than by replacing the static_assert by a run-time assertion.
Or am I thinking into a completely wrong direction?
Thanks
Hans
The first case requires a forward declaration of some kind, that's unavoidable.
The second case, though, can be handled with just a minor change.
#include <type_traits>
class CWnd {};
class MyClass2
{
public:
template<class T, class Y=T>
static void DoSomething(T* ptr) { static_assert(!std::is_same_v<Y,T>, "Don't do this"); }
};
template<> void MyClass2::DoSomething(CWnd* ptr) { /*some useful code*/ }
void foo()
{
int a;
CWnd b;
MyClass2::DoSomething(&a); // ERROR
MyClass2::DoSomething(&b); // OK
}
(partial answer)
To fix MyClass2, the usual trick is to make false depend on T, so that the first pass does not trigger the assert.
// dependent false
template <typename>
constexpr bool dep_false() { return false; }
class MyClass2
{
template<class T>
static void DoSomething(T* ptr) {
static_assert(dep_false<T>(), "Don't do this");
}
// lots more member functions, most of them 'static'
};
// specialization example
template<>
void MyClass2::DoSomething<int>(int* ptr) {
std::cout << "int* is OK\n";
}
As described in the MSDN library here I wanted to experiment a bit with the pimpl idiom. Right now I have a Foo.hpp with
template<typename T>
class Foo {
public:
typedef std::shared_ptr<Foo<T>> Ptr;
Foo();
private:
class Impl;
std::unique_ptr<Impl> pImpl;
};
where the T parameter isn't used yet. The implementation is stored in Foo.cpp
template<typename T>
class Foo<T>::Impl {
public:
int m_TestVar;
};
template<typename T>
Foo<T>::Foo() : pImpl(new Impl) {
this->pImpl->m_TestVar = 0x3713;
}
Currently the compiler has two errors and one warning:
use of undefined type 'Foo<T>::Impl'; ... vc\include\memory in line 1150
can't delete an incomplete type; ... vc\include\memory in line 1151
deletion of pointer to incomplete type 'Foo<T>::Impl'; no destructor called; ... vc\include\memory in line 1152
What is the concflict here and how could I resolve it?
Edit. Removed the call to std::make_shared - copy&paste fail based on one old version.
I have had a similar issue - we've a base class in our system called NamedComponent and I wanted to create a template which takes an existing named component and converts it into a pimpl facade.
What I did was separate the template into a header and an inline file, and create a function to cause the template to be instantiated. This allows the implementation to be in a library, with the template instantiations of the facade with that implementation, and for the client to be able to use the facade based on the template and a forward declaration of the implementation.
header 'Foo.h':
template<class T> class Foo
{
public:
Foo ();
virtual ~Foo();
private:
T *impl_;
public:
// forwarding functions
void DoIt();
};
inline functions 'Foo.inl':
#include "Foo.h"
template<class T> Foo<T>::Foo() :
impl_ ( new T )
{
}
template<class T> Foo<T>::~Foo()
{
delete impl_;
}
// forwarding functions
template<class T> void Foo<T>::DoIt()
{
impl_ -> DoIt();
}
// force instantiation
template<typename T>
void InstantiateFoo()
{
Foo<T> foo;
foo.DoIt();
}
implementation cpp file - include the template inline functions, define the implementation, reference the instantiation function:
#include "Foo.inl"
class ParticularImpl {
public:
void DoIt() {
std::cout << __FUNCTION__ << std::endl;
}
};
void InstantiateParticularFoo() {
InstantiateFoo<ParticularImpl>();
}
client cpp file - include the template header, forward declare the implementation and use the pimpl facade:
#include "Foo.h"
class ParticularImpl;
int main () {
Foo<ParticularImpl> bar;
bar.DoIt();
}
You may have to fiddle with the InstantiateFoo function's contents to force the compiler to instantiate all functions - in my case, the base called all the pimpl's functions in template methods so once one was referenced, they all were. You don't need to call the Instantiate functions, just link to them.
IMHO PIMPL doesn't make much sense with templates, unless you know all possible template parameters and that set is fairly small. The problem is, that you will either have the Impl implementation in the header file otherwise, as has been noted in the comments. If the number of possible T parameters is small, you still can go with the separation, but you'll need to declare the specialisations in the header and then explicitly instantiate them in the source file.
Now to the compiler error: unique_ptr<Impl> requires the definition of Impl to be available. You'll need to directly use new and delete in the ctor Foo::Foo and dtor Foo::~Foo, respectively instead and drop the convenience/safety of smart pointers.
I'm trying to build a wrapper around a managed class so I can call it from native code.
Here is the managed function :
void MyManagedFunction(MyStruct iStruct)
{
// Code according to what are the types of the 2 MyStruct members
}
struct MyStruct
{
public MyStruct(Object iValue1, Object iValue2) : this()
{
Value1 = iValue1; // Often contains DateTime::Now
Value2 = iValue2;
}
public Object Value1;
public Object Value2;
}
In my case, Value1 will almost always be System::DateTime::Now and the Value2 will almost always be a common data type (int, double, float, string, bool). I thought of making two templated function in the wrapper.
In the wrapper's .h I have the following :
#ifdef MYWRAPPER_EXPORTS
# define MYWRAPPER __declspec(dllexport)
#else
# define MYWRAPPER __declspec(dllimport)
#endif
class MYWRAPPER MyWrapper
{
public:
MyWrapper();
~MyWrapper();
template <class T> void MyNativeFunction(T iParam1)
{
MyStruct^ wStruct = gcnew MyStruct(System::DateTime::Now, iParam1);
//The class containing the managed function is a singleton
MyManagedClass::Instance->MyManagedFunction(wStruct);
}
template <class T, class W> void MyNativeFunction(T iParam1, W iParam2)
{
MyStruct^ wStruct = gcnew MyStruct(iParam1, iParam2);
//The class containing the managed function is a singleton
MyManagedClass::Instance->MyManagedFunction(wStruct);
}
};
This wrapper compiled without problem. The problem obviously occurred when I included the .h in the purely native code. Since I can't hide the content of the templated function, I have managed stuff visible on the native side which prevent the native code from compiling.
I was wondering if there was a workaround in order to achieve this. I don't mind if I'm limited into using only primitive types as parameters for the function. The best thing is if I was able to simply hide the content of the templated function in the native code so it only knows about the signature
Here's what I've tried/considered so far :
Converting the parameters to void* and call a function in which would call the managed one. By doing so, I can't cast the void* back to an object since I lose its type and using typeid to get the 'T' or 'W' type doesn't help since it vary from a compiler to another.
Overloading the function for every types I want to use. This is what I'll most likely use if I doesn't find a better solution. The problem is it means alot of overloading (especially for the 2 parameters function considering the number of combination)
If you know all the types your template will take, you can force instantiate it with those variables and thus put the code for the template functions in the source file instead of a header.
You can look at the example provided in Storing C++ template function definitions in a .CPP file
As he says you can do as below (copy-paste alert):
.h file
class foo
{
public:
template <typename T>
void do(const T& t);
};
.cpp file
template <typename T>
void foo::do(const T& t)
{
// Do something with t
}
template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);
What is the best pratice in regards to defining a template in C++?
template <class T>
class A
{
private:
// stuff
public:
T DoMagic()
{
//method body
}
}
Or:
template <class T>
class A
{
private:
// stuff
public:
T DoMagic();
}
template <class T>
A::T DoMagic()
{
// magic
}
Another way?
I seem to stumble over some controversy regarding this subject.
So; What path to choose?
This is completely a matter of style. That said however:
choose a way and stick to it -- either all inline, or all out, or mixed based on some rule
personally I use a 3 line rule. If the method body in the template is longer than 3 lines I move it outside.
There's no real reason not to include all definitions inline (they are inline from the compilers POV anyway), however, many people argue that keeping them separate is more clean, and allows the class definition to be more readable.
Use an increasing level of separation as the templates you write grow larger and more complex.
Performance will be the same no matter how you separate the definitions from the declarations, so your main concern here should be readability and maintainability.
When writing a simple template used only in one place, declare and define it inline with the declarations right in the CPP file where you're going to use it. There's no reason to force a global recompile if only one block of code needs this template.
file.cpp
template<class Gizmo> bool DoSomethingFancy()
{
// ...
}
For small template utilities used across translation units, define and declare them together in an H file:
utility.h
template<class Gizmo> bool DoSomethingUseful()
{
// ...
}
As your templates become more complex it will become more important to be able to view the declaration separately from the definition. At first, keep everything separate but in the same file:
utility.h
template<class Type> class Useful
{
bool FunctionA();
bool FunctionB();
};
template<class Type> bool Useful<Type>::FunctionA()
{
// ...
}
template<class Type> bool Useful<Type>::FunctionB()
{
// ...
}
But eventually even this will become unwieldly. When it does, separate it in to a header file for the declarations, and an INC file for the definitions. At the end of the header file, #include the INC file:
utility.h :
template<class Type> class MoreUseful
{
bool FunctionA();
bool FunctionB();
};
#include "utility.inc"
utility.inc :
template<class Type> bool MoreUseful<Type>::FunctionA()
{
// ...
}
template<class Type> bool MoreUseful<Type>::FunctionB()
{
// ...
}
This is a religious (style) issue. I prefer to define my functions outside of the template declaration for classes that have more than one method or the few methods are simple.
In either case, my understanding is that the template declaration and the method definitions must be in the same translation unit. This is because the template is more like a stencil, the compiler plugs a given type into the stencil and generates code for the given type.
Whatever you decide, just be consistent.
I usually define all the methods outside but each time I wish C++ had some sort of "template blocks":
template <class T>
struct A
{
T foo();
T bar(T * t);
T baz(T const & t);
};
template <class T> // Made-up syntax
{
T A::foo()
{
//...
}
T A::bar(T * t)
{
//...
}
T A::baz(T const & t)
{
//...
}
}
If the functions are non-trivial (i.e. more than one or two lines), consider defining them separately. This makes the interface of the class much easier to navigate, read and understand for the users of your class, who most likely shouldn't have to look at the actual implementation of each method.
For a one-off instance like your example, it makes little difference.
What happens when there are lots of templates with lots of variations? It then helps to put similar types of apples together, and similar types of oranges together away from them. Of course, this must all be done as intuitively as practical. That is greatly affected by the culture of programmers working with the code.
How do I inherit from a virtual template class, in this code:
// test.h
class Base {
public:
virtual std::string Foo() = 0;
virtual std::string Bar() = 0;
};
template <typename T>
class Derived : public Base {
public:
Derived(const T& data) : data_(data) { }
virtual std::string Foo();
virtual std::string Bar();
T data() {
return data_;
}
private:
T data_;
};
typedef Derived<std::string> DStr;
typedef Derived<int> DInt;
// test.cpp
template<typename T>
std::string Derived<T>::Foo() { ... }
template<typename T>
std::string Derived<T>::Bar() { ... }
When I try to use the DStr or DInt, the linker complain that there are unresolved externals, which are Derived<std::string>::Foo() and Derived<std::string>::Bar(), and the same for Derived<int>.
Did I miss something in my code?
EDIT:
Thanks all. It's pretty clear now.
You need to define template<typename T> std::string Derived<T>::Foo() { ... } and template<typename T>
std::string Derived<T>::Bar() { ... } in the header file. When the compiler is compiling test.cpp it doesn't know all the possible values of T that you might use in other parts of the program.
I think there are some compilers that have connections between the compiling and linking steps that notice references to missing template instantiations and go instantiate them from the .cpp file where they are declared. But I don't know which they are, and the functionality is exceedingly rare to find.
If you define them in the header file most compilers will emit them as a 'weak' symbol into every compilation unit in which they're referenced. And the linker will toss out all except for one definition of the weak symbol. This causes extra compilation time.
Alternately, there are syntaxes for explicitly instantiating templates and forcing the compiler to emit definitions right there. But that requires you to be aware of all the values T could possibly have and you will inevitably miss some.
You have to ensure that the member functions are instantiate for all the required types somewhere.
Usually this is accomplished by defining template functions inline in the header file where they are declared so that any use of the functions will cause them to be instantiated.
As an alternative, you can use explicit instantiations in the source file where you define them but this does require you to know in advance all the types that your template will ever be instantiated for.
This doesn't really have much to do with derivation. It's just a general rule with templates: with most compilers (anything but Comeau) you have to put the full implementation of a template where it's visible in every translation unit that will instantiate that template -- normally in the header.
Even with Comeau, you have to use the export keyword to make things work right. Since They're the only ones that implement export, chances are pretty good that you don't care much though.