I am learning c++ template technique.
I made a constructor with variadic template augments like following.
The class is simplified very much, so it does not have meaning.
However I could not call the function. Compiler tells me that it cannot call constructor directly.
How can I call it?
#include <utility>
class TemplateVariadicAugments {
public:
template <typename FutureInnterTemplateClass, typename... Args>
TemplateVariadicAugments(Args&&... args) : value_(std::forward<Args>(args)...) {}
virtual ~TemplateVariadicAugments() = default;
int value_;
};
void test_variadic_template_augments(void) {
TemplateVariadicAugments a = TemplateVariadicAugments::template TemplateVariadicAugments<int, int>(1);
}
In the form you wrote it, there is no way to call the constructor. First, in C++ you cannot call a constructor by it's name, even in trivial cases:
class A
{
public:
A() {}
};
void foo()
{
A::A(); // Illegal.
}
Then, as you can't call the constructor directly, you can't instantiate the template explicitly, so all template arguments must be deduced. But in your case FutureInnterTemplateClass cannot be deduced, as it's not used anywhere in the constructor.
The solution is to remove redundant argument from the constructor:
template <typename... Args>
TemplateVariadicAugments(Args&&... args) : value_(std::forward<Args>(args)...) {}
Now an object may be constructed as follows:
TemplateVariadicAugments obj(1);
and Args in this case wil lbe correctly deduced to int.
But in this case it's unclear what did you want to say with variadic template argument, as if you construct an object like this:
TemplateVariadicAugments obj(1, 2);
your value_ member initialization will become equivalent ti this code:
int value_(1, 2);
which is obviously ill-formed.
Related
I'm working on a C++11 code base and wondering how I can call any function on a member type passing arbitrary arguments. Note that since I'm using C++11 I can't use something like std::invoke.
I started creating a function template in the Outer class, but my initial try gives me a compile error.
#include <iostream>
#include <utility>
#include <type_traits>
struct Inner {
void bar(int x) {
std::cout << "Called: x=" << x << std::endl;
}
};
struct Outer {
explicit Outer(Inner *i) : b{i} {}
void foo(int) {}
Inner* b;
template <typename Func, typename ... Args>
void CallInner(Func&& f, Args&& ... args) {
b->f(std::forward<Args>(args)...);
}
};
int main() {
Inner inner{};
Outer outer(&inner);
outer.CallInner(&Inner::bar, 5);
}
Try it out yourself
Again, I would like to keep the signature of the function CallInner unchanged from the above sample code.
Since f is a pointer a member function it needs to be dereferenced first before being called:
(b->*f)(std::forward<Args>(args)...);
You don't have much choice with regards to changing the signature, because at least one additional template is required.
The correct syntax is a little bit more complicated:
struct Outer {
explicit Outer(Inner *i) : b{i} {}
void foo(int) {}
Inner* b;
template <typename Ret, typename ...FuncArgs, typename ... Args>
void CallInner(Ret (Inner::*f)(FuncArgs...), Args&& ... args) {
(b->*f)(std::forward<Args>(args)...);
}
};
The first parameter to CallInner must be a method pointer, and, in a template context, it needs to be templated not just by a set of variadic template parameters, FuncArgs, but also its return type, Ret. Then you also need a second set of variadic template parameters for the forwarding references of the arguments you're forwarding (which may not necessarily be the same as FuncArgs, hence the need for a separate set of variadic template types).
I have a template-heavy code at hand in which classes which are supposed to be used as template parameters to the user code, have different constructor signatures. My problem is, that I have not found a good way to call the constructors of the templated Classes in my user code. A mimimal working example could look like this:
#include <string>
#include <iostream>
#include <memory>
class ShortConstructorInLibrary {
std::string myName;
static const int tag = 1;
public:
ShortConstructorInLibrary(std::string name) :
myName(name) {
}
};
class LongConstructorInLibrary {
private:
int a;
double b;
public:
static const int tag = 2;
LongConstructorInLibrary(int arg1, double arg2) :
a(arg1), b(arg2) {
}
};
//above is library code
template<typename T>
class MyClass {
std::shared_ptr<T> member_p;
//i want to call right constructor for both cases:
public:
MyClass() {
//how do i call the different constructors properly?!
member_p = std::shared_ptr<T>(new T("test"));
}
};
int main() {
MyClass<ShortConstructorInLibrary> obj; //works
//MyClass<LongConstructorInLibrary> obj2; // wrong constructor signature
}
Here I have two classes in a library, one with a long and unrelated constructor signature, one with a short one. I want to be able to use both of them as template parameters. In my userClass I somehow have to define what arguments to pass to the constructors depending on the type passed.
I can not use a simple if() because the compiler will check both signatures and one will be wrong. I can not use c++17 for "if constexpr(){}".
I can pass the template Parameter "ShortConstructorInLibrary" to my class and call its constructor perfectly fine, but when I use the other class it will, of course, fail for a wrong constructor signature. I used an ugly trick so far that i implemented two helper methods where i pass a pointer and then let the two methods implement the constructor calls, but that seems ugly to me. I also fiddled around with std::enable_if<> but did not get very far. #Mohit proposed to use partial template specialization, but in the real world code the Short ConstructorInLibrary class is itself templated with a couple of ...templated template arguments. To give you an idea:
‘class CFEM_LOP<Dune::PDELab::QkLocalFiniteElementMap<Dune::GridView<Dune::DefaultLeafGridViewTraits<const Dune::YaspGrid<2> > >, double, double, 1ul>, EngwHillenKnapp2014<MedicalDataManager<double, Dune::YaspGrid<2> >, Dune::YaspGrid<2> >, CFEM_L2OP<Dune::PDELab::QkLocalFiniteElementMap<Dune::GridView<Dune::DefaultLeafGridViewTraits<const Dune::YaspGrid<2> > >, double, double, 1ul> >, Dune::YaspGrid<2> >’
I fell that trying to specialize my user code will be a hell of a mess.
What is the correct way to implement constructor calls of possibly varying signatures?
any hints would be appreciated!
(ubuntu 16.04, gcc)
Try partial specialization method for achieving this and I used std::make_shared for creating std::shared_ptrs
class ShortConstructorInLibrary
{
std::string myName;
static const int tag = 1;
public:
ShortConstructorInLibrary(std::string name) :
myName(name)
{
}
};
class LongConstructorInLibrary
{
private:
int a;
double b;
public:
static const int tag = 2;
LongConstructorInLibrary(int arg1, double arg2) :
a(arg1), b(arg2)
{
}
};
//above is library code
template<typename T>
class MyClass
{
std::shared_ptr<T> member_p;
//i want to call right constructor for both cases:
public:
MyClass()
{
//how do i call the different constructors properly?!
member_p = std::make_shared<T>("test");
}
};
template<>
MyClass<LongConstructorInLibrary>::MyClass()
{
member_p = std::make_shared<LongConstructorInLibrary>(0, 0.0); // pass you values.
}
int main()
{
MyClass<LongConstructorInLibrary> obj; //works
//MyClass<LongConstructorInLibrary> obj2; // wrong constructor signature
}
The constructor of MyClass is supposed to create an object of type T. Assume that each T passed as template parameter has a different constructor signature, so you need to pass the arguments needed for the construction of T to the class MyClass and forward these arguments. This is possible since c++11 with variadic templates, i.e.
template <class T>
struct MyClass
{
std::shared_ptr<T> member_p;
template <class... Args>
MyClass(Args&&... args)
: member_p(std::make_shared<T>(std::forward<Args>(args)...))
{}
};
int main() {
MyClass<ShortConstructorInLibrary> obj1("test");
MyClass<LongConstructorInLibrary> obj2(1, 2.0);
}
You just need to be carefull, with variadic universal constructor arguments, since this also covers the copy/move constructor. In order to not deactivate these with your written constructor, you have to add a little bit of enable_if code. Since you use Dune, you can simply apply a common pattern:
template <class... Args, Dune::disableCopyMove<MyClass, Args...> = 0>
MyClass(Args&&... args)
: member_p(std::make_shared<T>(std::forward<Args>(args)...))
{}
The disableCopyMove is a wrapper around an enable_if that produces a substitution failure, in case you pass an MyClass const& or MyClass&& to the constructor, so that copy and move constructors are not hidden by your self-defined constructor. The = 0 is necessary, since the type defined by this enable_if wrapper is int and the = 0 is the default value of this non-type template parameter, so that you don't need to specify it yourself.
Unlike function declarations with parameter packs, I've found that classes require the type for each argument in the angle brackets...
Component<IntegerPair, int, int> temp(40, 5);
...which seems redundant. Here's how I defined Component:
template<typename T, class... T_Args>
class Component
{
public:
Component(T_Args... args)
: m_data(args...)
{}
T m_data;
};
Is there a way to remove int, int from the above statement?
If so, is it ok to remove it?
Also, is my way of instantiation m_data safe? When using
std::forward<T_Args>(args)... my compiler told me I didn't have a
constructor that could convert all of the argument types.
One way is to make the constructor a template:
#include <utility>
struct IntegerPair {
IntegerPair(int, int) {}
};
template<typename T>
class Component
{
public:
template<typename... T_Args>
Component(T_Args&&... args)
: m_data(std::forward<T_Args>(args)...)
{}
T m_data;
};
int main()
{
Component<IntegerPair> c {1,2};
}
This is functionally equivalent to std::vector and its member function emplace_back. It's perfectly ok, IMO. The error messages are pretty cryptic, as usual in template constructs like this, but this can be mitigated with an appropriate static_assert.
template parameter deduction only work for function calls so the basic pattern to achieve what you want looks like this:
template<typename T, class... T_Args>
Component<T, T_Args...> makeComponent(T_Args&&... args) {
return Component<T, T_Args...>(std::forward<T_Args>(args)...);
}
Usage:
auto c = makeComponent<IntegerPair>(1, 1)
I often find the need to use the following pattern:
template<typename T>
class SomeClass : public Base {
SomeClass(const T& t) {...}
...
};
template<typename T>
SomeClass<T>* makeSomeClass(const T& t) {
return new SomeClass<T>(t);
}
And to use it:
Base* = makeSomeClass(123);
This is useful when I don't want to explicitly specify T because it is a very complex (function types, etc') and the function argument can deduce the type implicitly.
Is there a way to do this without the extra "make" function? Why does template deduction work only in function arguments and not in constructor arguments?
No, there is no way to do this without an extra make function.
The reason it doesn't work with constructors is because it would be ridiculously complicated. Consider this:
template <typename T>
struct Foo
{
Foo(const T& val) { ... }
Foo(const Foo<T>& other) { ... } // Copy constructor
};
Foo<int> x;
What if I then call:
Foo(x);
Does that give me a Foo< Foo<int> > or am I calling the copy constructor for a Foo<int>?
It would be ambiguous in too many places, so the extra function is necessary.
Note that you can automate the create of make functions a little by using template templates:
template <template <typename> class TemplateClass, typename Type>
TemplateClass<Type> make(const Type& x)
{
return TemplateClass<Type>(x);
}
Then you can use:
make<SomeClass>(123); // returns a SomeClass<int>
It does work in constructor arguments, if the constructor is itself a template. The difference is that when you use your helper, you're using a function template, where the compiler can deduce the type. Without the helper, you're using a class template, where the compiler would have to somehow deduce the type before calling the (non-template) constructor.
Is there a way without the extra function? No there isn't. Why the deduction works only for functions? Because with functions you actually provide arguments. If it were allowed for classes, then the only way to deduce the template parameters would be in case when a constructor was called for initialization, which makes lots of additional rules and exceptions and complicates things,
I wish to have a non-template class with a template constructor with no arguments.
As far as I understand, it's impossible to have it (because it would conflict with the default constructor - am I right?), and the workaround is the following:
class A{
template <typename U> A(U* dummy) {
// Do something
}
};
Maybe there is a better alternative for this (or a better workaround)?
There is no way to explicitly specify the template arguments when calling a constructor template, so they have to be deduced through argument deduction. This is because if you say:
Foo<int> f = Foo<int>();
The <int> is the template argument list for the type Foo, not for its constructor. There's nowhere for the constructor template's argument list to go.
Even with your workaround you still have to pass an argument in order to call that constructor template. It's not at all clear what you are trying to achieve.
You could use a templated factory function instead of a constructor:
class Foo
{
public:
template <class T> static Foo* create() // could also return by value, or a smart pointer
{
return new Foo(...);
}
...
};
As far as I understand, it's impossible to have it (because it would conflict with the default constructor - am I right?)
You are wrong. It doesn't conflict in any way. You just can't call it ever.
template<class...>struct types{using type=types;};
template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;
the above helpers let you work with types as values.
class A {
template<class T>
A( tag<T> );
};
the tag<T> type is a variable with no state besides the type it caries. You can use this to pass a pure-type value into a template function and have the type be deduced by the template function:
auto a = A(tag<int>{});
You can pass in more than one type:
class A {
template<class T, class U, class V>
A( types<T,U,V> );
};
auto a = A(types<int,double,std::string>{});
Some points:
If you declare any
constructor(including a templated
one), the compiler will refrain from
declaring a default constructor.
Unless you declare a copy-constructor (for class X one
that takes X or X& or X const
&) the compiler will generate the
default copy-constructor.
If you provide a template constructor for class X which takes
T const & or T or T& then the
compiler will nevertheless generate a
default non-templated
copy-constructor, even though you may think that it shouldn't because when T = X the declaration matches the copy-constructor declaration.
In the latter case you may want to provide a non-templated copy-constructor along with the templated one. They will not conflict. When X is passed the nontemplated will be called. Otherwise the templated
HTH
You could do this:
class C
{
public:
template <typename T> C(T*);
};
template <typename T> T* UseType()
{
static_cast<T*>(nullptr);
}
Then to create an object of type C using int as the template parameter to the constructor:
C obj(UseType<int>());
Since you can't pass template parameters to a constructor, this solution essentially converts the template parameter to a regular parameter. Using the UseType<T>() function when calling the constructor makes it clear to someone looking at the code that the purpose of that parameter is to tell the constructor what type to use.
One use case for this would be if the constructor creates a derived class object and assigns it to a member variable that is a base class pointer. (The constructor needs to know which derived class to use, but the class itself doesn't need to be templated since the same base class pointer type is always used.)
Here's a workaround.
Make a template subclass B of A. Do the template-argument-independent part of the construction in A's constructor. Do the template-argument-dependent part in B's constructor.
It is perhaps easier and more intuitive to rely on std::in_place_type_t<T> which is used in std::variant, std::any, etc for exactly the same purpose:
#include <utility>
class A {
template <typename U>
A(std::in_place_type_t<U>) {
// Do something
}
};
A a(std::in_place_type_t<MyType>{});
try doing something like
template<class T, int i> class A{
A(){
A(this)
}
A( A<int, 1>* a){
//do something
}
A( A<float, 1>* a){
//do something
}
.
.
.
};
Just simple to add a dummy variable like
class A {
template<typename T>
A(const T&, int arg1, int arg2);
}