Is it possible to declare a template without parameters?
I have a template like:
template < int i, int j>
class X{
int doSomething() { return i+j;}
}
and now i want to use this Template in another class, but i don't know its parameter cause they are variable. But i would like to save different templates in a variable like this :
class Foo {
X var;
void setVar ( const X &newVar) { var = newVar; }
X getVar () { return var;}
}
Is there a way to save different types of the template in one variable ? or pointer ?
Thx for help
Templates are resolved at compile time; your template parameters can't depend on values that aren't known until runtime. Furthermore, each instance of a template is a different type: X<1, 2> and X<3, 4> are different just like two classes Foo and Bar are different; a variable of the one type can't hold a value of the other. You can't have a variable whose type is just X, because X is not a type (it's a template).
It doesn't make sense for a template to have no parameters; you don't need a template at all in that case. It's not clear why you're trying to use templates to add two variables. You probably want to just use a class that holds two integers passed to its constructor:
class X {
private:
int i, j;
public:
X(int i, int j): i(i), j(j) { }
int doSomething() const { return i + j; }
};
This will let you have variables of type X, and you can construct different instances of X with different values for i and j based on variables at runtime.
You would want to use type erasure. boost::any provides a good implementation which might suffice for your use case. Here's the example from there modified for your situation :
BOOST_TYPE_ERASURE_MEMBER((canDoSomething), doSomething, 0)
class Foo {
using X = any<canDoSomething<int(void)>>;
X var;
void setVar ( const X &newVar) { var = newVar; }
X getVar () { return var;}
int DoSomethingWithX() { return var.doSomething();}
}
Related
In the example below, is it possible to create a function getX that walks over the variant cases and get the x variable?
#include <variant>
class A {
int x = 0;
};
class B {
int x = 1;
};
class C {
int x = 1;
};
std::variant<A, B, C> variant;
One obvious solution would be:
int getX(std::variant<A, B, C>& variant) {
if (std::holds_alternative<A>(variant)) {
} else //...
}
but then every time I add a new variant it'd be tedious to write code that treats the new case.
Is there a more automated, perhaps constexpr way of doing this? I think it's even possible to do for different variable names in each class. The one call that works should be the chosen one for the class.
That's a "visit". You can do this:
#include <variant>
struct A {
int x = 0;
};
struct B {
int x = 1;
};
struct C {
int x = 1;
};
std::variant<A, B, C> var = A{};
int main() {
int n = std::visit([](auto & obj) {return obj.x;}, var);
}
Note, passing visit a generic lambda (taking an auto parameter) is actually a template, so whatever type is in the variant, that's the type of reference obj will be. I had to change your classes to structs so that the data was accessible.
I just want to ask if there are any uses for passing variables in cpp as template arguments
template<int a> struct foo {
int x = a;
};
int main() {
foo<2> bar;
std::cout << bar.x;
}
Something like this compiles, works and cout's 2 but the same thing can be done by doing
struct foo {
int x;
foo(int a) : x(a) {}
};
int main() {
foo bar(2);
std::cout << bar.x;
}
So what is the point of using variables in template arguments? I can also see a big flaw in using the first method: the variable a uses memory and isn't destructed after x is changed, as it would be after the constructor is called in the second example. It might be helpful if you showed some reasonable uses for that.
When you pass a variable through a template argument, it can be used in compile time.
For example, if you need to create a statically sized array in your class, you could use the template argument to pass the size of your array:
template <int TSize>
class Foo {
[...] // Do whatever you need to do with mData.
private:
std::array<int, TSize> mData;
};
There are many uses for constants in template parameters.
Static Sizes
This is how you would start implementing something like a std::array.
template <typename T, size_t SIZE>
struct Array {
T data[SIZE];
}
Template parameters are always usable in a constexpr context, so they can be used as sizes for statically sized arrays.
Providing Compile-Time Parameters to Algorithms
Another use is parametrizing algorithms like in the following code sample.
We have a uint32_t in ARGB order but to store it in a file, we might need to reorder it to BGRA or RGBA. We know the order at compile time, so we could use an ArgbOrder template variable.
enum class ArgbOrder { ARGB, RGBA, BGRA };
struct ChannelOffsets {
unsigned a;
unsigned r;
unsigned g;
unsigned b;
};
// and we can get a constexpr lookup table from this enum
constexpr ChannelOffsets byteShiftAmountsOf(ArgbOrder format)
{
...
}
template <ArgbOrder order>
void encodeArgb(uint32_t argb, uint8_t out[4])
{
// We can generate the shift amounts at compile time.
constexpr detail::ChannelOffsets shifts = shiftAmountsOf(order);
out[0] = static_cast<u8>(argb >> shifts.a);
out[1] = static_cast<u8>(argb >> shifts.r);
out[2] = static_cast<u8>(argb >> shifts.g);
out[3] = static_cast<u8>(argb >> shifts.b);
}
void example() {
encodeArgb<ArgbOrder::BGRA>(12345);
}
In this example, we can select the appropriate lookup table at compile time and have zero runtime cost. All that needs to happen at runtime is 4 shifts.
Feature Toggles
We can use bool template variables to toggle features in our code, like for example:
template <bool handleZeroSpecially>
int div(int x, int y) {
if constexpr (handleZeroSpecially) {
return y == 0 ? 0 : x / y;
}
else {
return x / y;
}
}
I am trying to specialize std::unordered_map for a class X with a custom hash and a custom equality. The problem is that both the equality and hash functions do not depend only on the object(s) of class X but also on data in another (fixed) object of another class Y. Here is a toy example (with only the hash function) of what I want to do:
#include <unordered_map>
using namespace std;
struct Y {
bool b;
struct X {
size_t i;
};
size_t hash(const X &x) {
return x.i + b;
}
unordered_map<X, int, hash> mymap;
};
The problem is that the function hash in the template specialization is a method and the compiler complains ("call to non-static member function without an object argument"). What I want is that y.mymap uses y.hash(). Any way to do this?
Note that in the real code Y is also a template, in case it matters.
Thanks!
EDIT: To clarify, instead of the boolean b in my code I have a vector with data that is needed in comparing objects of type X. Some data is added when an X is created, so the vector is not constant, but the data for a given X does not change after it is added, so the hash for a given X never changes (so in a sense it depends only on X as required for a hash). The main reason I use this approach is to save memory since this data is a lot and is usually shared.
You can use function<size_t(X const&)> and e.g. bind, but as type erasure is not necessary in this case, here is a simpler solution:
struct Y {
bool b;
struct X {
size_t i;
bool operator==(X x) const {return i == x.i;}
};
size_t hash(const X &x) {
return x.i + b;
}
struct Hasher {
Y* this_;
template <typename T>
auto operator()(T&& t) const
-> decltype(this_->hash(std::forward<T>(t))) {
return this_->hash(std::forward<T>(t));
}
};
unordered_map<X, int, Hasher> mymap;
Y() : b(false),
mymap(0, {this}) {}
};
As mentioned by #dyp in the comments, you have to be careful with special member functions since we implicitly store this in mymap - i.e. the compiler-generated definitions would copy the this_ pointer. An example implementation of the move constructor could be
Y(Y&& y) : b(y.b), mymap(std::make_move_iterator(std::begin(y.mymap)),
std::make_move_iterator(std::end (y.mymap)), 0, {this}) {}
Unfortunately what you want to do is not legal. See 17.6.3.5/Table 26:
h(k) The value returned shall depend only on the argument k.
It's pretty clear that you aren't allowed to have the hash depend on a member of Y as well as X.
EDIT: Just in case you meant for b to be const in your Y class there is a solution (I didn't compile this yet, I will if I get a chance):
struct Y
{
explicit Y(bool config) : b(config), hash_(config), mymap(0, hash_) { }
const bool b;
struct X
{
size_t i;
};
struct Hash
{
explicit Hash(bool b) : b_(b) { }
size_t operator()(const X& x) const
{
return x.i + b_;
}
private:
bool b_;
};
Hash hash_;
unordered_map<X, int, Hash> mymap;
};
I currently have the following non templated code:
class Vector{
public:
double data[3];
};
static Vector *myVariable;
void func() {
myVariable->data[0] = 0.;
}
int main() {
myVariable = new Vector();
func();
}
I then want to template the dimension :
template<int DIM> class Vector{
public:
double data[DIM];
};
static Vector<3>* myVariable;
void func() {
myVariable->data[0] = 0.;
}
int main() {
myVariable = new Vector<3>();
func();
}
But I finally want to template my variable as well, with the dimension :
template<int DIM> class Vector{
public:
double data[DIM];
};
template<int DIM> static Vector<DIM> *myVariable;
void func() {
myVariable->data[0] = 0.;
// or perform any other operation on myVariable
}
int main() {
int dim = 3;
if (dim==3)
myVariable = new Vector<3>();
else
myVariable = new Vector<4>();
func();
}
However, this last version of the code produces an error : this static variable cannot be templated ("C2998: Vector *myVariable cannot be a template definition").
How could I possibly correct this error without a complete redesign (like inheriting the templated Vector class from a non templated class, which would require more expensive calls to virtual methods , or manually creating several myVariables of different dimensions) ? Maybe I'm just tired and don't see an obvious answer :s
Edit: Note that this code is a minimal working code to show the error, but my actual implementation templates the dimension for a full computational geometry class, so I cannot just replace Vector by an array. I see that there doesn't seem to be a solution to my problem.
Thanks!
It's been a while, but I've used constants in the template declaration before. I eventually went another direction with what I was working on, so I don't know if it'll ultimately be your solution either. I think the problem here is that any templated variable must know its template argument at compile time.
In your example, Vector<3> and Vector<4> are different types, and cannot be assigned to the same variable. That's why template<int DIM> static Vector<DIM> *myVariable doesn't make any sense; it doesn't have a discernible type.
template<int DIM> static Vector<DIM> *myVariable;
This is not allowed by the language specification. End of the story.
And since I don't understand the purpose of your code, or what you want to achieve, I cannot suggest any better alternative than simply suggesting you to try using std::vector<T>. It's also because I don't know how much am I allowed to redesign your code, and the way you use it, to make your code work.
You can use std::array to template-ize the dimension but you can't cast the pointer of one dimension to the pointer of another.
I think I found!
template<int DIM> class Vector{
public:
double data[DIM];
};
static void *myVariable;
template<int DIM>
void func() {
((Vector<DIM>*)myVariable)->data[0] = 0.;
// or perform any other operation on myVariable
}
int main() {
int dim = 3;
if (dim==3)
{
myVariable = (void*) new Vector<3>();
func<3>();
}
else
{
myVariable = (void*) new Vector<4>();
func<4>();
}
}
Vector<3> and Vector<4> are entirely different types and have no formal relation to one another. The fact that they are superficially similar from your point of view doesn't matter.
If you want them to be equivalent up to a certain type, we have a name for that: interfaces
template <typename Scalar = float>
class BasicVector {
public:
typedef Scalar * iterator;
virtual ~ BasicVector () {}
virtual size_t size () const = 0;
virtual iterator begin () = 0;
virtual iterator end () = 0;
};
template <unsigned N, typename Scalar = float>
class Vector : public BasicVector <Scalar> {
Scalar m_elements [N];
public:
using Scalar :: iterator;
size_t size () const {return N;}
iterator begin () {return m_elements;}
iterator end () {return m_elements + N;}
};
int main () {
BasicVector * a;
a = new Vector <3>;
a = new Vector <4>;
}
I have a class
template <unsigned int N>
class StaticVector {
// stuff
};
How can I declare and define in this class a static factory method returning a StaticVector<3> object, sth like
StaticVector<3> create3dVec(double x1, double x2, double x2);
?
"How can I declare and define in this class"
In what class? You've defined a class template, not a class. You can't call a static function of a class template itself, you have to call a particular version of the static function that's part of a real class.
So, do you want the template (and hence all instantiations of it) to have a function returning a StaticVector<3>, or do you want one particular instantiation of that template to have a function returning a StaticVector<3>?
If the former:
template <unsigned int N>
struct SV {
int contents[N];
static SV<3> get3dVec(int x, int y, int z) {
SV<3> v;
v.contents[0] = x;
v.contents[1] = y;
v.contents[2] = z;
return v;
}
};
int main() {
SV<3> v = SV<1>::get3dVec(1,2,3);
}
works for me.
If the latter (you only want get3dVec to be a member of SV<3>, not of all SV<whatever>), then you want template specialisation:
template <unsigned int N>
struct SV {
int contents[N];
};
template<>
struct SV<3> {
int contents[3]; // must be re-declared in the specialization
static SV<3> get3dVec(int x, int y, int z) {
SV<3> v;
v.contents[0] = x;
v.contents[1] = y;
v.contents[2] = z;
return v;
}
};
int main() {
SV<3> v = SV<1>::get3dVec(1,2,3); // compile error
SV<3> v = SV<3>::get3dVec(1,2,3); // OK
}
If for no other reason than to make the calling code look nicer by omitting the basically irrelevant template parameter, I agree with Iraimbilanja that normally a free function (in a namespace if you're writing for re-use) would make more sense for this example.
C++ templates mean that you don't need static functions as much in C++ as you do in Java: if you want a "foo" function that does one thing for class Bar and another thing for class Baz, you can declare it as a function template with a template parameter that can be Bar or Baz (and which may or may not be inferred from function parameters), rather than making it a static function on each class. But if you do want it to be a static function, then you have to call it using a specific class, not just a template name.
Something like :
template< unsigned int SIZE >
StaticVector< SIZE > createVec( const std::tr1::array< double, SIZE >& values )
{
StaticVector< SIZE > vector;
for( int i = 0; i < values.size(); ++i ) // here assuming that StaticVector have [] operator to access values on write
{
vector[i] = values[i];
}
return vector;
}
... or a variant would certainly work. (did'nt test it)
Usage would be:
std::tr1::array< double, 3 > vectorValues = { 10.0, 10.0, 42.0 };
StaticVector<3> vector1 = createVector( vectorValues ); // if the compiler can guess the size from the array information
StaticVector<3> vector2 = createVector<3>( vectorValues ); // if you have to specify the size
An alternative would be to replace std::tr1::array by a basic array but it would be using raw arrays at your own risks :)
First, i believe you originally mean to return
StaticVector<N>
Instead of always a specialization with N==3 . So, what you want to do is writing it like this:
template <unsigned int N>
class StaticVector {
public:
// because of the injected class-name, we can refer to us using
// StaticVector . That is, we don't need to name all template
// parameters like StaticVector<N>.
static StaticVector create3dVec(double x1, double x2, double x2) {
// create a new, empty, StaticVector
return StaticVector();
}
};
If you really want to always return a 3dVector, you would probably want to restrict it to N==3, so that for example StaticVector<4>::create3dVec doesn't work. You can do that using the technique described here.
If you want to have a function like createVec that works with any size, you probably want to replace the parameters with an array. You can do otherwise, but that's advanced and requires some macro tricks applied with boost::preprocessor. It's not worth it i think. The next C++ version will provide variadic templates for this purpose. Anyway,consider using something like this:
I think it would only complicate this unnecessarily here. A quick solution is to use a boost::fusion::vector instead, putting it into the class template instead of the version above:
static StaticVector createVec(double (&values)[N]) {
// create a new, empty, StaticVector, initializing it
// with the given array of N values.
return StaticVector();
}
You could use it with
double values[3] = {1, 2, 3};
StaticVector<3> v = StaticVector<3>::createVec(values);
Note that it accepts an array by reference. You can't give it a pointer. That is because it matches the use of parameters: You couldn't provide less or more arguments for the other way too. It will also protect you from cases like this:
// oops, values is a null pointer!
StaticVector<3> v = StaticVector<3>::createVec(values);
An array never can be a null pointer. Of course if you like, you can always change the array parameter to a pointer. It would just be my personal preference :)
#litb
I wanted to return a 3-element vector. The reason is that these vectors are supposed to be geometric entities, so there is no need for N to be too high (I'm not a string physicist, so I don't work in 11-dimensional spaces). I wanted to create a template to avoid duplicating code but keep 1-, 2- and 3-dimensional vectors as separate types.