Is there a straightforward way for defining a partial specialization of a C++ template class given a numerical constant for one of the template parameters? I'm trying to create special constructors for only certain kinds of template combinations:
template <typename A, size_t B> class Example
{
public:
Example() { };
A value[B];
};
template <typename A, 2> class Example
{
public:
Example(b1, b2) { value[0] = b1; value[1] = b2; };
};
This example won't compile, returning an error Expected identifier before numeric constant in the second definition.
I've had a look through a number of examples here and elsewhere, but most seem to revolve around specializing with a type and not with a constant.
Edit:
Looking for a way to write a conditionally used constructor, something functionally like this:
template <typename A, size_t B> class Example
{
public:
// Default constructor
Example() { };
// Specialized constructor for two values
Example<A,2>(A b1, A b2) { value[0] = b1; value[1] = b2; };
A foo() {
A r;
for (size_t i = 0; i < b; ++b)
r += value[i];
return r;
}
// Hypothetical specialized implementation
A foo<A, 2>() {
return value[0] + value[1];
}
A value[B];
};
You need to put the specialization in the correct place:
template <typename A> class Example<A,2>
If you want to create a subclass:
template <typename A> class ExampleSpecialization : public Example<A,2>
The behavior for specializing on typedefs is similar to the behavior for specializing on an integer parameter.
I think this might work:
#include <iostream>
template <typename A, size_t B>
class Example {
public:
Example()
{
Construct<B>(identity<A, B>());
}
A foo()
{
return foo<B>(identity<A, B>());
}
private:
template <typename A, size_t B>
struct identity {};
template <size_t B>
void Construct(identity<A, B> id)
{
for (size_t i = 0; i < B; ++i)
{
value[i] = 0;
}
std::cout << "default constructor\n";
}
template <size_t B>
void Construct(identity<A, 2> id)
{
value[0] = 0;
value[1] = 0;
std::cout << "special constructor\n";
}
template <size_t B>
A foo(identity<A, B> id)
{
A r = 0;
for (size_t i = 0; i < B; ++i)
{
r += value[i];
}
std::cout << "default foo\n";
return r;
}
template <size_t B>
A foo(identity<A, 2> id)
{
std::cout << "special foo\n";
return value[0] + value[1];
}
A value[B];
};
int main()
{
Example<int, 2> example; // change the 2 to see the difference
int n = example.foo();
std::cin.get();
return 0;
}
Sorry, I just copy and pasted it from my test project. It's not really "specialization" in a way, it just calls overloads to specialized functions. I'm not sure if this is what you want and imo this isn't very elegant.
If memory serves, it should be more like:
template <typename A, size_t B> class Example
{
public:
Example() { };
A value[B];
};
template <typename A> class Example<A, 2>
{
public:
Example(A b1, A b2) { value[0] = b1; value[1] = b2; };
};
I don't think this is quite allowable as-is though -- there's nothing defining the types of b1 and/or b2 in the specialized version.
Edit [based on edited question]: Yes, a template specialization produces a new type that's not really related to the base from which it's specialized. In particular, the two do not share any of the implementation. You can't (by specializing a class template) produce a single type that uses one of two different ctors, depending on the value of a non-type parameter.
You can try something like this:
template<size_t s>
struct SizeTToType { static const size_t value = s; };
template<bool> struct StaticAssertStruct;
template<> struct StaticAssertStruct<true> {};
#define STATIC_ASSERT(val, msg) { StaticAssertStruct<((val) != 0)> ERROR_##msg; (void)ERROR_##msg;}
template <typename A, size_t B>
class Example
{
public:
Example() { };
Example(A b1){ value[0] = b1; }
Example(A b1, A b2) {
STATIC_ASSERT(B >= 2, B_must_me_ge_2);
value[0] = b1; value[1] = b2;
}
A foo() { return in_foo(SizeTToType<B>()); }
protected:
template<size_t C>
A in_foo(SizeTToType<C>) {
cout << "univ" << endl;
A r;
for (size_t i = 0; i < B; ++i)
r += value[i];
return r;
}
A in_foo(SizeTToType<2>){
cout << "spec" << endl;
return value[0] + value[1];
}
A value[B];
};
Working example on http://www.ideone.com/wDcL7
In templates if you are not using method it won't exists in compiled code, so this solution shouldn't make executable bigger because of ctors you can't use with some specialized class (for example Example<int, 1> should not have Example(A b1, A b2) ctor).
If you're goal is to only have to override a few methods/constructors in your specializations then maybe consider a generic base class to hold the common implementation for all Example templates so you don't have to rewrite it in every specialization you come up with.
For example:
template < typename A, size_t B >
class ExampleGeneric {
public:
// generic implementation of foo inherited by all Example<A,B> classes
void foo() {
A r;
for (size_t i = 0; i < B; ++i)
r += value[i];
return r;
}
// generic implementation of bar inherited by all Example<A,B> classes
void bar() {
A r;
for (size_t i = 0; i < B; ++i)
r *= value[i];
return r;
}
A values[B];
};
template < typename A, size_t B >
class Example : public ExampleGeneric<A,B> {
public:
//default to generic implementation in the general case by not overriding anything
};
//*** specialization for 2
template < typename A >
class Example<A,2> : public ExampleGeneric<A,2>{
public:
// has to be provided if you still want default construction
Example() {
}
//extra constructor for 2 parameters
Example( A a1, A a2 ) {
values[0] = a1;
values[1] = a2;
}
// specialization of foo
void foo() {
return values[0] + values[1];
}
// don't override bar to keep generic version
};
#include <iostream>
using namespace std;
template<typename _T, size_t S>
class myclass {
_T elem[S];
public:
myclass() {
for (int i = 0; i < S; i++) {
elem[i] = i;
}
}
void Print() {
for (int i = 0; i < S; i++) {
cout << "elem[" << i << "] = " << elem[i] << endl;
}
}
};
int main(int argc, char **argv)
{
myclass < int, 10 > nums;
nums.Print();
myclass < int, 22 > nums1;
nums1.Print();
}
That worked on my linux machine with
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-48)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Related
I would like to create a heterogeneous structure to store pointers to some classes so that I can loop through it and call a write() function.
The idea is this:
#include <boost/variant.hpp>
#include <vector>
template< typename T>
class A
{
public:
A(){}
~A(){}
void write();
private:
T data;
};
template< typename T>
void A<T>::write()
{
std::cout << data << std::endl;
}
int main()
{
A<int> one;
A<double> two;
typedef boost::variant<A<int>*, A<double>* > registry;
std::vector<registry> v;
v.push_back(&one);
v.push_back(&two);
for(unsigned int i =0; i< v.size(); i++)
{
v[i]->write();
}
}
However, this code does not compile. Showing the error:
error: base operand of ‘->’ has non-pointer type ‘__gnu_cxx::__alloc_traits<std::allocator<boost::variant<A<int>*, A<double>*> > >::value_type {aka boost::variant<A<int>*, A<double>*>}’
v[i]->write();
How can I fix this? I would also appreciate ideas on the implementation
v[i] returns a boost::variant<A<int>*, A<double>*> instead of a pointer to an instance of A, so you cannot use operator-> on it. You need to use boost::apply_visitor to visit the content fo the variant.
for(unsigned int i = 0; i < v.size(); i++) {
boost::apply_visitor([](auto a) { a->write(); }, v[i]);
}
Demo.
Since lambda uses auto as a parameter type is a feature of C++14, in C++11, you need to create a callable class with a template operator() as the visitor, as shown below:
struct Visitor {
using result_type = void;
template<typename T>
result_type operator()(A<T>* a) const { a->write(); }
};
for(unsigned int i = 0; i < v.size(); i++) {
boost::apply_visitor(Visitor{}, v[i]);
}
Demo.
Based on the previous answer I built:
class myVisitor
: public boost::static_visitor<>
{
public:
template< typename T>
void operator() (A<T>* a) const
{
a->write();
}
};
And use it in the code as:
for(auto x: v)
{
boost::apply_visitor(myVisitor(), x);
}
Or with a common base class as:
class tst
{
public:
virtual ~tst() {}
virtual void write() = 0;
};
template< typename T>
class A : public tst
{
public:
A(){}
~A(){}
void write();
private:
T data;
};
int main()
{
A<int> one;
A<double> two;
std::vector<tst*> v;
v.push_back(&one);
v.push_back(&two);
for(auto x: v)
{
x->write();
}
}
What do you think?
in the following code example I am about to call concrete foo() function with already initialized arguments vect via run() method. For compilation I use VS19 with C++17. In the following I am not sure about my usage of std::apply... Any kind of help is welcomed ;)
#include <iostream>
#include <vector>
#include <tuple>
using namespace std;
template<typename ...T>
struct Base {
vector<int> vect;
Base(){
static const std::size_t size = sizeof...(T);
for (int i = 0; i < size; i++)
vect.push_back((i+1)*(i+1)); //some initialization
}
};
template<typename ...T>
struct Derived : public Base<T...> {
virtual int foo(T...) = 0;
int lastResult;
void run() {
if (this->vect.size() > 0) {
lastResult = std::apply(foo, this->vect);
}else{
lastResult = -1;
cout << "0 arguments case" << endl;
}
}
};
struct D0 : public Derived<> {
int foo() override { return 0; }
};
struct D1 : public Derived<int> {
int foo(int a) override { return a * a; }
};
struct D2 : public Derived<int,int> {
int foo(int a, int b) override { return a + b; }
};
int main() {
D0 d0;
cout << d0.foo() << endl; // 0
//d0.run(); //vect = {}, lastResult = -1, "0 arguments case"
D1 d1;
cout << d1.foo(1) << endl; // 1
//d1.run(); //vect = {1} -> lastResult = 1
D2 d2;
cout << d2.foo(1, 2) << endl; // 3
//d2.run(); //vect = {1,4} -> lastResult = 5
cin.get();
}
Using std::index_sequence from C++14 helps with this kind of stuff:
Make a second version of run that takes a sequence of size_t template arguments, and use std::index_sequence_for to fill them:
template <size_t... Is>
void runImpl(std::index_sequence<Is...>) { ... }
void run() { return runImpl(std::index_sequence_for<T...>{}); }
Then, in runImpl, you can expand the template integers to pass vector values as function parameters:
if (this->vect.size() > 0) {
lastResult = foo(Base<T...>::vect[Is]...);
}else{
lastResult = -1;
cout << "0 arguments case" << endl;
}
Demo: https://godbolt.org/z/ZGroAH
In the following I am not sure about my usage of std::apply...
I see two problems in your usage of std::apply()
(1) std::apply() require a std::tuple, or similar, for second argument. For "or similar" I mean "or std::array or std::pair".
So your std::vector doesn't works.
I suppose you can use a std::array.
I propose the following Base
template<typename ...T>
struct Base {
std::array<int, sizeof...(T)> vect;
template <int ... Is>
Base (std::integer_sequence<int, Is...>) : vect {{ (Is+1)*(Is+1) ... }}
{ }
Base () : Base{std::make_integer_sequence<int, sizeof...(T)>{}}
{ }
};
(2) the first argument of std::apply() isn't compatible with a (non static) method.
But you can wrap it's use in a lambda, so I propose
lastResult = std::apply([=](auto ... args)
{ return this->foo(args...); },
this->vect);
I want to define additional variables in a struct based on the type in template, something like this:
template<typename CONFIG>
struct Test
{
int a;
int b;
if (std::is_same<CONFIG, MyClass>::value)
{
// additional variables if the CONFIG type is MyClass
int c;
int d;
}
// functions
void func()
{
a = 0;
b = 0;
if (std::is_same<CONFIG, MyClass>::value)
{
c = 0;
d = 0;
}
}
}
How should I do that? Thanks!
This is a use case for template specialization. You have a primary template like
template<typename CONFIG>
struct Test
{
int a;
int b;
// functions
void func()
{
a = 0;
b = 0;
}
};
and then a specialization for MyClass like
template <>
struct Test<MyClass>
{
int a;
int b;
int c;
int d;
// functions
void func()
{
a = 0;
b = 0;
c = 0;
d = 0;
}
};
A variant that follows your pseudo-code a bit more (not saying that it is a better approach than the other answer):
template<typename CONFIG>
struct TestAdditionalMembers {};
template<>
struct TestAdditionalMembers<MyClass>
{
int c;
int d;
};
template<typename CONFIG>
struct Test : TestAdditionalMembers<CONFIG>
{
int a;
int b;
// functions
void func()
{
a = 0;
b = 0;
if constexpr(std::is_same<CONFIG, MyClass>::value)
{
this->c = 0;
this->d = 0;
}
}
};
The additional members are provided through inheritance and explicit specialization of the class template. Since c and d are not dependent names, but only exist for certain template parameters, you will need to refer to them with this->c, etc. (this is always a dependent name).
Inside a function the condition needs to be checked by a if constexpr, since at-runtime check would be too late. (The code inside the if must compile even if the condition is always false.)
Based on walnuts answer, you could collect all your conditional actions and member variables in a specialization that you inherit if you want to avoid type traits and constexpr-if's.
template<typename T>
struct completions {
void func_completion() {} // does nothing
};
template<>
struct completions<MyClass> {
int c;
int d;
void func_completion() {
c = 0;
d = 0;
}
};
template<typename CONFIG>
struct Test : completions<CONFIG> {
int a;
int b;
// functions
void func() {
a = 0;
b = 0;
this->func_completion();
}
};
Consider this pseudo-snippet:
class SomeClass
{
public:
SomeClass()
{
if(true)
{
fooCall = [](auto a){ cout << a.sayHello(); };
}
else
{
fooCall = [](auto b){ cout << b.sayHello(); };
}
}
private:
template<typename T>
std::function<void(T)> fooCall;
};
What I want is a class member fooCall which stores a generic lambda, which in turn is assigned in the constructor.
The compiler complains that fooCall cannot be a templated data member.
Is there any simple solution on how i can store generic lambdas in a class?
There is no way you'll be able to choose between two generic lambdas at run-time, as you don't have a concrete signature to type-erase.
If you can make the decision at compile-time, you can templatize the class itself:
template <typename F>
class SomeClass
{
private:
F fooCall;
public:
SomeClass(F&& f) : fooCall{std::move(f)} { }
};
You can then create an helper function to deduce F:
auto makeSomeClassImpl(std::true_type)
{
auto l = [](auto a){ cout << a.sayHello(); };
return SomeClass<decltype(l)>{std::move(l)};
}
auto makeSomeClassImpl(std::false_type)
{
auto l = [](auto b){ cout << b.sayHello(); };
return SomeClass<decltype(l)>{std::move(l)};
}
template <bool B>
auto makeSomeClass()
{
return makeSomeClassImpl(std::bool_constant<B>{});
}
I was not able to store std::function<> as a generic lambda in the class directly as a member. What I was able to do was to specifically use one within the class's constructor. I'm not 100% sure if this is what the OP was trying to achieve but this is what I was able to compile, build & run with what I'm suspecting the OP was aiming for by the code they provided.
template<class>
class test {
public: // While testing I changed this to public access...
// Could not get object below to compile, build & run
/*template<class U = T>
static std::function<void(U)> fooCall;*/
public:
test();
};
template<class T>
test<T>::test() {
// This would not compile, build & run
// fooCall<T> = []( T t ) { std::cout << t.sayHello(); };
// Removed the variable within the class as a member and moved it here
// to local scope of the class's constructor
std::function<void(T)> fooCall = []( auto a ) { std::cout << a.sayHello(); };
T t; // created an instance of <Type T>
fooCall(t); // passed t into fooCall's constructor to invoke the call.
}
struct A {
std::string sayHello() { return "A say's Hello!\n"; }
};
struct B {
std::string sayHello() { return "B say's Hello!\n"; }
};
int main() {
// could not instantiate an object of SomeClass<T> with a member of
// a std::function<> type that is stored by a type of a generic lambda.
/*SomeClass<A> someA;
SomeClass<B> someB;
someA.foo();
someB.foo();*/
// Simply just used the object's constructors to invoke the locally stored lambda within the class's constructor.
test<A> a;
test<B> b;
std::cout << "\nPress any key & enter to quit." << std::endl;
char c;
std::cin >> c;
return 0;
}
With the appropriate headers the above as is should compile, build & run giving the output below (At least in MSVS 2017 on Windows 7 64bit did); I left comments where I ran into errors and tried multiple different techniques to achieve a working example, errors occurred as others suggested and I found even more while working with the above code. What I was able to compile, build and run came down to this simple bit of code here without the comments. I also added another simple class to show it will work with any type:
template<class>
class test {
public:
test();
};
template<class T>
test<T>::test() {
std::function<void( T )> fooCall = []( auto a ) { std::cout << a.sayHello(); };
T t;
fooCall( t );
}
struct A {
std::string sayHello() { return "A say's Hello!\n"; }
};
struct B {
std::string sayHello() { return "B say's Hello!\n"; }
};
struct C {
int sayHello() { return 100; }
};
int main() {
test<A> testA;
test<B> testB;
test<C> testC;
std::cout << "\nPress any key & enter to quit." << std::endl;
char c;
std::cin >> c;
return 0;
}
Output:
A say's Hello!
B say's Hello!
100
Press any key & enter to quit
I don't know if this will help the OP directly or indirectly or not but if it does or even if it doesn't it is still something that they may come back to and build off of.
you can simply use a template class or...
If you can get away with using c++17, you could make fooCall's type std::function<void(const std::any&)> and make a small wrapper for executing it.
method 1 : simply use a template class (C++14).
method 2 : seems to mimic the pseudo code exactly as the OP intended (C++17).
method 3 : is a bit simpler and easier to use than method 2 (C++17).
method 4 : allows us to change the value of fooCall (C++17).
required headers and test structures for the demo :
#include <any> //not required for method 1
#include <string>
#include <utility>
#include <iostream>
#include <functional>
struct typeA {
constexpr const char * sayHello() const { return "Hello from A\n"; }
};
struct typeB {
const std::string sayHello() const { return std::string(std::move("Hello from B\n")); }
};
method 1 :
template <typename T>
class C {
const std::function<void(const T&)> fooCall;
public:
C(): fooCall(std::move([](const T &a) { std::cout << a.sayHello(); })){}
void execFooCall(const T &arg) {
fooCall(arg);
}
};
int main (void) {
typeA A;
typeB B;
C<typeA> c1;
C<typeB> c2;
c1.execFooCall(A);
c2.execFooCall(B);
return 0;
}
method 2 :
bool is_true = true;
class C {
std::function<void(const std::any&)> fooCall;
public:
C() {
if (is_true)
fooCall = [](const std::any &a) { std::cout << std::any_cast<typeA>(a).sayHello(); };
else
fooCall = [](const std::any &a) { std::cout << std::any_cast<typeB>(a).sayHello(); };
}
template <typename T>
void execFooCall(const T &arg) {
fooCall(std::make_any<const T&>(arg));
}
};
int main (void) {
typeA A;
typeB B;
C c1;
is_true = false;
C c2;
c1.execFooCall(A);
c2.execFooCall(B);
return 0;
}
method 3 :
/*Note that this very closely resembles method 1. However, we're going to
build off of this method for method 4 using std::any*/
template <typename T>
class C {
const std::function<void(const std::any&)> fooCall;
public:
C() : fooCall(std::move([](const std::any &a) { std::cout << std::any_cast<T>(a).sayHello(); })) {}
void execFooCall(const T &arg) {
fooCall(std::make_any<const T&>(arg));
}
};
int main (void) {
typeA A;
typeB B;
C<typeA> c1;
C<typeB> c2;
c1.execFooCall(A);
c2.execFooCall(B);
return 0;
}
method 4 :
/*by setting fooCall outside of the constructor we can make C a regular class
instead of a templated one, this also complies with the rule of zero.
Now, we can change the value of fooCall whenever we want.
This will also allow us to do things like create a container that stores
a vector or map of functions that each take different parameter types*/
class C {
std::function<void(const std::any&)> fooCall; //could easily be replaced by a vector or map
public:
/*could easily adapt this to take a function as a parameter so we can change
the entire body of the function*/
template<typename T>
void setFooCall() {
fooCall = [](const std::any &a) { std::cout << std::any_cast<T>(a).sayHello(); };
}
template <typename T>
void execFooCall(const T &arg) {
fooCall(std::make_any<const T&>(arg));
}
};
int main (void) {
typeA A;
typeB B;
C c;
c.setFooCall<typeA>;
c.execFooCall(A);
c.setFooCall<typeB>;
c.execFooCall(B);
return 0;
}
Output from Any method
Hello from A
Hello from B
Given this code:
template < int I >
class Foo
{
public:
int v;
Foo() { v = I; }
virtual ~Foo() {}
};
class Bar : public Foo<0>, public Foo<3>
{
public:
template < int I >
int getValue() { return Foo<I>::v; }
};
int main() {
Bar b;
cout << b.getValue<0>() << endl; // prints 0
cout << b.getValue<3>() << endl; // prints 3
cout << b.getValue<4>() << endl; // compiler error
return 0;
}
Is it possible to iterate over all Foo<i> classes from which Bar inherits? We can assume that i is between 0 and some maximum N. In pseudocode:
for ( int i = 0; i < N; i++ )
{
if ( Bar inherits from `Foo<i>` )
{
cout << Foo<i>::v << endl;
}
}
Here you go (live example):
struct _do { template <typename... A> _do(A&&...) { } };
template <int... I>
class Bar_impl : public Foo<I>...
{
public:
template < int K >
int getValue() { return Foo<K>::v; }
template <typename F>
void loop(F&& f) { _do{(std::forward<F>(f)(getValue<I>()), 0)...}; }
};
using Bar = Bar_impl<0,3>;
Now Bar implementation holds all indices of base classes in variadic parameter I... and derives all base classes Foo<I>... in a variadic fashion.
Function loop iterates over all bases using the auxiliary struct _do. You can pass an arbitrary function, lambda or function object f to loop. Then f will be called on getValue<I>() for all I..., i.e., on member v of every base class.
You use this as follows:
void print(int i) { cout << i << " "; }
int main() {
Bar b;
b.loop(print); // prints 0 3
cout << endl;
}
In other words, you don't need to detect if an object is an instance of some class. You make the object know its own bases by construction.
Now you may realize that if you make Foo a template on the member type (instead of int), you are quite close to start building your own very basic tuple.