I need to allow the user to change members of two data structures of the same type at the same time. For example:
struct Foo { int a, b; }
Foo a1 = {1,2}, a2 = {3,4};
dual(a1,a2)->a = 5;
// Now a1 = {5,2} and a2 = {5,2}
I have a class that works and that change first a1 and then copy a1 into a2. This is fine as long as:
the class copied is small
the user doesn't mind about everything being copied, not only the part modified.
Is there a way to obtain this behavior:
dual(a1,a2)->a = 5;
// Now a1 = {5,2} and a2 = {5,4}
I am opened to alternative syntax, but they should stay simple, and I would like to avoid things like:
set_members(a1, a2, &Foo::a, 5);
members(a1, a2, &Foo::a) = 5;
or anything involving specifying explictely &Foo::
[Edit]
I should be more precise. The point is to work with a graph library. The library works on directed graph, but usage dictate that given two vertices, v1 and v2, if there is an edge v1->v2, then there will be an edge v2->v1. And these two edges have, very often (but not always) the same properties. So the current implementation now allows:
G.edge(v1,v2)->b = 5; // Only v1->v2 is modified
G.arc(v1,v2)->a = 10;
// Now G.edge(v2,v1) is set to G.edge(v1,v2) after the modification a = 10 (i.e. b = 5 too)
And I would like the notation to imply that only a is modified.
Relatively simple solution with Boost.Lambda:
#include <boost/lambda/lambda.hpp>
using namespace boost::lambda;
template<typename T, typename U, typename V>
void dual(const T& functor, U& a1, V& a2)
{
functor(a1);
functor(a2);
}
struct Foo
{
int a;
};
struct Bar
{
char a;
};
int main()
{
Foo a1;
Bar a2;
dual(_1 = 5, a1.a, a2.a);
}
Extending dual() with variadic templates / Boost.Preprocessor shenanigans is left as an exercise to the reader.
//to get the desired syntax
template<class T>
class SetPropertyProxy
{
public:
SetPropertyProxy(T& _v1, T& _v2)
: a(_v1, _v2) {}
class A_Property_Proxy
{
public:
A_Property_Proxy(T& _v1, T& _v2): v1(_v1), v2(_v2) {}
A_Property_Proxy& operator = (T::A_Property_Type val)
{
v1.a = val;
v2.a = val;
return *this;
}
private:
T& v1;
T& v2;
}
//public member "a"
A_Property_Proxy a;
};
//helper function
template<class T>
SetPropertyProxy<T> dual(T& a , T& b)
{ return SetPropertyProxy<T>(a,b); }
//usage
dual(a,b).a = 5; //calls A_Property_Proxy::operator =
It can be improved further making A_Property_Proxy class reusable by parameterizing by property type and taking references to properties instead of references to property containers (edges in this case)
template<class U>
class Property_Proxy
{
public:
Property_Proxy(U& _v1prop, U& _v2prop): v1prop(_v1prop), v2prop(_v2prop) {}
Property_Proxy& operator = (U val)
{
v1prop = val;
v2prop = val;
return *this;
}
private:
U& v1prop;
U& v2prop;
}
Edit (putting this here because comments don't have formatting)
So are you saying that your current code has lots of this:
G.edge(v3,v4)->a = 2;
G.edge(v3,v4)->b = 2;
G.edge(v4,v5)->a = 6;
G.edge(v4,v5)->b = 6;
And a very little bit of this:
G.edge(v5,v6)->a = 4;
G.edge(v5,v6)->b = 7;
And your goals are [1] make it easier to spot those special cases [2] less verbose code?
----- original answer, may be irrelevant now -----
Here's a general idea, there are lots of possible improvements:
class MagicBag
{
private:
// you could make the whole class a template
// instead of hard-coding Foo..
vector<Foo *> m_vec;
public:
// store references to the items
void Add(Foo *f) { m_vec->push_back(f); }
// you can do overloads instead of these setters...
void set_a(int val) {
for (vector<Foo>::iterator i = m_vec.start(); i != m_vec.end(); ++i)
(*i)->a = val;
}
void set_b(int val) {
for (vector<Foo>::iterator i = m_vec.start(); i != m_vec.end(); ++i)
(*i)->b = val;
}
}
Usage:
Foo a1 = {1,2}, a2 = {3,4};
MagicBag mb;
mb.Add(&a1);
mb.Add(&a2);
mb.set_a(5); // now a1.a = 5 and a2.a = 5
// etc.
This is easier semantically in languages which support Properties, such as C#. There the final syntax would be:
mb.a = 5;
By introducing an abuse of templates I can get most of the desired syntax. This compiles and works, but no guarantees are made about it. It requires adding some macros the struct to be used and requires use of set_* instead of direct assignment.
#include <iostream>
#define PROPERTY_MAP(ClassName) \
struct hidden_Mapper { \
ClassName * m_d1; \
ClassName * m_d2; \
hidden_Mapper(Data * d1, Data * d2) : \
m_d1(d1), m_d2(d2) {}
#define DECLARE_PROPERTY(name)\
template <typename ValueType> \
void set_##name(const ValueType & value) \
{ m_d1->name = value; m_d2->name = value; } \
#define END_PROPERTY_MAP };
template<typename ClassType>
typename ClassType::hidden_Mapper dual(ClassType & d1, ClassType & d2)
{
return typename ClassType::hidden_Mapper(&d1, &d2);
}
struct Data
{
int a;
float b;
PROPERTY_MAP(Data)
DECLARE_PROPERTY(a)
DECLARE_PROPERTY(b);
END_PROPERTY_MAP
};
int main()
{
Data d1, d2;
dual(d1, d2).set_a(5);
dual(d1, d2).set_b(5.7);
std::cout << d1.a << d2.a << d1.b << d2.b <<std::endl;
}
struct proxy {
struct column {
column(T &a, T &b);
column& operator=(T);
T &a, &b;
};
proxy(U &A, U &B);
column operator[](int i) { return column(A[i], B[i]; }
U &A, &B;
};
proxy(A, B)[0] = 5;
// or you could be evil, overload ",", and get this syntax
(A, B)[0] = 5;
or some sort of variation
Related
I'm trying to create my own variant class that can be cast to and from many types. This leads to issues with ambiguous calls for operators like '+' and '-'. Is it possible to create a preference for which casts occur to avoid this?
#include <string>
class Variant
{
public:
Variant() {}
Variant(int i) : mData(std::to_string(i)) {}
Variant(double d) : mData(std::to_string(d)) {}
operator int() const { return lround(atof(mData.c_str())); }
operator double() const { return atof(mData.c_str()); }
private:
std::string mData;
};
int main() {
Variant v = 1.2;
int i = v; //fine
double d = v; //fine
double x = v - 1.0; //error, ambiguous, would be nice to prefer a double cast
}
You may do something like
#include <iostream>
#include <string>
#include <type_traits>
template <typename T>
struct S
{
template <typename T2>
T2 operator-(const T2& i_lhs) const
{
static_assert(std::is_convertible_v<T, T2>);
auto result = static_cast<T2>(m_member);
result -= i_lhs;
return result;
}
T m_member = 20;
};
And use it
int main()
{
auto s = S<int>();
auto s3 = s - 10.0;
std::cout << s3 << std::endl;
}
One more thing, so as to make the behaviour intuitive, provide a number of operators (i.e. Numeric + Variant, Variant + Numeric, and Variant + Variant).
And, the provided code returns a double. It may be more intuitive to return a new Variant.
Let say you have the following classes:
class Data
{
public:
int a;
int b;
};
class DataOther
{
public:
int a;
int b;
};
class Line
{
public:
Data Right;
Data Left;
};
class LineOther
{
public:
DataOther Right;
DataOther Left;
}
I have quite a few classes that are structured this way, and when I want to run code over both "sides" of the data I typically do something like this:
enum class Side { RIGHT, LEFT };
template<typename T>
auto GetBySide(const Side &side, T &data) -> decltype(data.Right) &
{
return side == Side::Left ? data.Left : data.Right;
}
And then in the code:
Line l;
LineOther lOther;
for(auto &side: {Sides::LEFT, Sides::Right})
{
auto &d = GetBySide(side, l);
auto &dOther = GetBySide(side, lOther);
// Do some stuff with the data
}
Now the down side of this, is that it's run-time so not much optimization can be done, though I suppose a compiler might unroll the loop.
Any other ideas on how to structure the code?
If you worry about unrolling, you may replace:
Line l;
LineOther lOther;
for (auto &side: {Sides::LEFT, Sides::Right})
{
auto &d = GetBySide(side, l);
auto &dOther = GetBySide(side, lOther);
// Do some stuff with the data
}
by something like:
template <Side side>
void foo(Line& l, LineOther& lOther) {
auto &d = GetBySide(side, l);
auto &dOther = GetBySide(side, lOther);
// Do some stuff with the data
}
and
Line l;
LineOther lOther;
foo<Sides::LEFT>(l, lOther);
foo<Sides::Right>(l, lOther);
"I have quite a few classes that are structured this way" it seems that you can leave only one of them. Or at least utilize inheritance or other technique to avoid duplication:
// Declare base class instead of copypasting fields.
class BaseLine
{
public:
int Right{};
int Left{};
};
class Line: public BaseLine
{};
class LineOther: public BaseLine
{};
int main()
{
Line l;
l.Right = 45; l.Left = 89;
LineOther lOther;
lOther.Right = 74; lOther.Left = 33;
// Use pointer to member to iterate over fields.
for(auto p_side: {&BaseLine::Right, &BaseLine::Left})
{
::std::cout << (l.*p_side) << ::std::endl;
::std::cout << (lOther.*p_side) << ::std::endl;
}
}
Online compiler
I have been working on a priority queue using a binary heap and have developed a class for this as shown below.
#include <iostream>
#include <type_traits>
template<class T, int N>
class BinaryHeap{
template<class T1>
class has_less_than_operator
{
private:
class no{};
template<class X>
static auto has(X&& t) -> decltype (t.operator < (t));
static no has(...);
public:
enum {
value = !std::is_same<
decltype(has( std::declval<T1>() )),
no>::value
};
};
static_assert(std::is_copy_assignable<T>::value &&
std::is_copy_constructible<T>::value,
"Must be copy assignable and constructable");
public:
BinaryHeap() : used_(0){
}
BinaryHeap(BinaryHeap const& other) = default;
BinaryHeap& operator = (BinaryHeap const& other) = default;
inline T& max(){
return elements_[FIRST];
}
inline T const & max() const{
return elements_[FIRST];
}
void insert(T const& item){
elements_[++used_] = item;
swim(used_);
}
inline bool full() const{
return used_ == N;
}
void deleteMax(){
std::swap(elements_[used_],elements_[FIRST]);
sink(FIRST);
elements_[used_--] = T();
}
private:
template<class T1>
class has_dereference_operator
{
private:
class no{};
template<class X>
static auto has(X&& t) -> decltype (t.operator * ());
static no has(...);
public:
enum {
value = !std::is_same<
decltype(has( std::declval<T1>() )),
no>::value
};
};
inline bool parent_less(int position,std::integral_constant<int,0> i){
return elements_[ position / 2] < elements_[position];
}
inline bool parent_less(int position,std::integral_constant<int,1> i){
return *(elements_[ position / 2]) < *(elements_[position]);
}
void swim(int position){
while(position > 1 && parent_less(position,std::integral_constant<int, has_dereference_operator<T>::value>()))
{
std::swap(elements_[ position / 2], elements_[position]);
position /= 2;
}
}
inline int which_less(int p1, int p2, std::integral_constant<int,0> i){
return (elements_[ p1] < elements_[p2]) ? p1 : p2;
}
inline int which_less(int p1, int p2, std::integral_constant<int,1> i){
return (*(elements_[ p1]) < *(elements_[p2])) ? p1 : p2;
}
inline int which_greater(int p1, int p2, std::integral_constant<int,0> i){
return (elements_[ p1] < elements_[p2]) ? p2 : p1;
}
inline int which_greater(int p1, int p2, std::integral_constant<int,1> i){
return (*(elements_[ p1]) < *(elements_[p2])) ? p2 : p1;
}
void sink(int position){
while(position * 2 <= used_){
int first = position * 2;
if(first > used_) break;
int greater_child = which_greater(first, first + 1, std::integral_constant<int, has_dereference_operator<T>::value>());
int lesser = which_less(greater_child, position, std::integral_constant<int, has_dereference_operator<T>::value>());
if(lesser == greater_child)
break;
std::swap(elements_[greater_child], elements_[position]);
position = greater_child;
}
}
inline int current_position() const{
return used_ + 1;
}
static const int MAX = N + 1;
static const int FIRST = 1;
static const int LAST = N;
T elements_[MAX];
int used_;
};
int main(int argc, const char * argv[])
{
BinaryHeap<int, 10> b;
b.insert(1);
b.insert(20);
b.insert(21);
b.insert(3);
b.insert(2);
std::cout << "Max: " << b.max() << std::endl;
b.deleteMax();
std::cout << "Max: " << b.max() << std::endl;
return 0;
}
Although I have this working I need to deal with the differences in comparing say a pointer / shared pointer say using dereference operator and values just using them as is. I am currently using SFINAE to do this based on if the class has operator *.
Is this the right way to achieve this?
Blair
The problem with using heuristics like this is that it's not always what the client of your code wants you to do, and you don't provide a way to change the behavior. Someday a client may want to use your class to store pointers and actually sort them with std::less<T> instead of dereferencing (BinaryHeap<void*,32> for example). Even with non-pointers, a client may simply want a differing ordering than that imposed by <.
When the Standard Library needs to perform comparison it usually uses std::less<T> by default but provides a way for the client to override that choice (e.g. std::priority_queue or std::sort). If I was writing your class, I would parameterize it by comparison operator defaulting to std::less<T> just like the Standard Library would. I would also provide a handy dereferencing comparator template to make it easy for clients using pointers to order by pointees.
I have a bunch of vector classes. I have a 2D point vec2_t, a 3D point vec3_t and a 4D point vec4_t (you often want these when you have do graphics; this is graphics code, but the question has a generic C++ flavour).
As it is now, I have vec2_t declaring two members x and y; vec3_t subclasses vec2_t and has a third member z; vec4_t subclasses vec3_t and adds a w member.
I have a lot of near-duplicate code for operator overloading computing things like distances, cross products, multiplication by a matrix and so on.
I've had a few bugs where things have been sliced when I've missed to declare an operator explicitly for the subclass and so on. And the duplication bugs me.
Additionally, I want to access these members as an array too; this would be useful for some OpenGL functions that have array parameters.
I imagine that perhaps with a vec_t<int dimensions> template I can make my vector classes without subclassing. However, this introduces two problems:
How do you have a variable number of members that are also array entries, and ensure they align? I don't want to lose my named members; vec.x is far nicer than vec.d[0] or whatever imo and I'd like to keep it if possible
How do you have lots of the more expensive methods in a CPP source file instead of the header file when you take the templating route?
One approach is this:
struct vec_t {
float data[3];
float& x;
float& y;
float& z;
vec_t(): x(data[0]), y(data[1]), z(data[2]) {}
};
Here, it correctly aliases the array members with names, but the compiler I've tested with (GCC) doesn't seem to work out they are just aliases and so the class size is rather large (for something I might have an array of, and want to pass e.g. as a VBO; so size is a big deal) and how would you template-parameterise it so only the vec4_t had a w member?)
A possible solution (I think).
main.cpp:
#include <iostream>
#include "extern.h"
template <int S>
struct vec_t_impl
{
int values[S];
bool operator>(const vec_t_impl<S>& a_v) const
{
return array_greater_than(values, a_v.values, S);
}
void print() { print_array(values, S); }
virtual ~vec_t_impl() {}
};
struct vec_t2 : vec_t_impl<2>
{
vec_t2() : x(values[0]), y(values[1]) {}
int& x;
int& y;
};
struct vec_t3 : vec_t_impl<3>
{
vec_t3() : x(values[0]), y(values[1]), z(values[2]) {}
int& x;
int& y;
int& z;
};
int main(int a_argc, char** a_argv)
{
vec_t3 a;
a.x = 5;
a.y = 7;
a.z = 20;
vec_t3 b;
b.x = 5;
b.y = 7;
b.z = 15;
a.print();
b.print();
cout << (a > b) << "\n";
return 0;
}
extern.h:
extern bool array_greater_than(const int* a1, const int* a2, const size_t size);
extern void print_array(const int* a1, const size_t size);
extern.cpp:
#include <iostream>
bool array_greater_than(const int* a1, const int* a2, const size_t size)
{
for (size_t i = 0; i < size; i++)
{
if (*(a1 + i) > *(a2 + i))
{
return true;
}
}
return false;
}
void print_array(const int* a1, const size_t size)
{
for (size_t i = 0; i < size; i++)
{
if (i > 0) cout << ", ";
std::cout << *(a1 + i);
}
std::cout << '\n';
}
EDIT:
In an attempt to address the size issue you could change the member reference variables to member functions that return a reference.
struct vec_t2 : vec_t_impl<2>
{
int& x() { return values[0]; }
int& y() { return values[1]; }
};
Downside to this is slightly odd code:
vec_t2 a;
a.x() = 5;
a.y() = 7;
Note: Updated and improved the code a lot.
The following code uses a macro to keep the code clean and partial specialization to provide the members. It relies heavily on inheritence, but that makes it very easy to extend it to arbitary dimensions. It's also intended to be as generic as possible, that's why the underlying type is a template parameter:
// forward declaration, needed for the partial specializations
template<unsigned, class> class vec;
namespace vec_detail{
// actual implementation of the member functions and by_name type
// partial specializations do all the dirty work
template<class Underlying, unsigned Dim, unsigned ActualDim = Dim>
struct by_name_impl;
// ultimate base for convenience
// this allows the macro to work generically
template<class Underlying, unsigned Dim>
struct by_name_impl<Underlying, 0, Dim>
{ struct by_name_type{}; };
// clean code after the macro
// only need to change this if the implementation changes
#define GENERATE_BY_NAME(MEMBER, CUR_DIM) \
template<class Underlying, unsigned Dim> \
struct by_name_impl<Underlying, CUR_DIM, Dim> \
: public by_name_impl<Underlying, CUR_DIM - 1, Dim> \
{ \
private: \
typedef vec<Dim, Underlying> vec_type; \
typedef vec_type& vec_ref; \
typedef vec_type const& vec_cref; \
typedef by_name_impl<Underlying, CUR_DIM - 1, Dim> base; \
protected: \
struct by_name_type : base::by_name_type { Underlying MEMBER; }; \
\
public: \
Underlying& MEMBER(){ \
return static_cast<vec_ref>(*this).member.by_name.MEMBER; \
} \
Underlying const& MEMBER() const{ \
return static_cast<vec_cref>(*this).member.by_name.MEMBER; \
} \
}
GENERATE_BY_NAME(x, 1);
GENERATE_BY_NAME(y, 2);
GENERATE_BY_NAME(z, 3);
GENERATE_BY_NAME(w, 4);
// we don't want no pollution
#undef GENERATE_BY_NAME
} // vec_detail::
template<unsigned Dim, class Underlying = int>
class vec
: public vec_detail::by_name_impl<Underlying, Dim>
{
public:
typedef Underlying underlying_type;
underlying_type& operator[](int idx){
return member.as_array[idx];
}
underlying_type const& operator[](int idx) const{
return member.as_array[idx];
}
private:
typedef vec_detail::by_name_impl<Underlying, Dim> base;
friend struct vec_detail::by_name_impl<Underlying, Dim>;
typedef typename base::by_name_type by_name_type;
union{
by_name_type by_name;
underlying_type as_array[Dim];
} member;
};
Usage:
#include <iostream>
int main(){
typedef vec<4, int> vec4i;
// If this assert triggers, switch to a better compiler
static_assert(sizeof(vec4i) == sizeof(int) * 4, "Crappy compiler!");
vec4i f;
f.w() = 5;
std::cout << f[3] << '\n';
}
Of course you can make the union public, if you want to, but I think accessing the members through the function is better.
Note: The above code compiles cleanly without any warnings on MSVC10, GCC 4.4.5 and Clang 3.1 with -Wall -Wextra (/W4 for MSVC) and -std=c++0x (only for static_assert).
This would be one way to do it:
#include<cstdio>
class vec2_t{
public:
float x, y;
float& operator[](int idx){ return *(&x + idx); }
};
class vec3_t : public vec2_t{
public:
float z;
};
Edit: #aix is right in saying that it's non-standard and could cause problems. Perhaps a more appropriate solution would then be:
class vec3_t{
public:
float x, y, z;
float& operator[](int idx){
static vec3_t v;
static int offsets[] = {
((char*) &(v.x)) - ((char*)&v),
((char*) &(v.y)) - ((char*)&v),
((char*) &(v.z)) - ((char*)&v)};
return *( (float*) ((char*)this+offsets[idx]));
}
};
Edit #2: I have an alternative, where it's possible to only write your operators once, and not end up with a bigger class, like so:
#include <cstdio>
#include <cmath>
template<int k>
struct vec{
};
template<int k>
float abs(vec<k> const&v){
float a = 0;
for (int i=0;i<k;i++)
a += v[i]*v[i];
return sqrt(a);
}
template<int u>
vec<u> operator+(vec<u> const&a, vec<u> const&b){
vec<u> result = a;
result += b;
return result;
}
template<int u>
vec<u>& operator+=(vec<u> &a, vec<u> const&b){
for (int i=0;i<u;i++)
a[i] = a[i] + b[i];
return a;
}
template<int u>
vec<u> operator-(vec<u> const&a, vec<u> const&b){
vec<u> result;
for (int i=0;i<u;i++)
result[i] = a[i] - b[i];
return result;
}
template<>
struct vec<2>{
float x;
float y;
vec(float x=0, float y=0):x(x), y(y){}
float& operator[](int idx){
return idx?y:x;
}
float operator[](int idx) const{
return idx?y:x;
}
};
template<>
struct vec<3>{
float x;
float y;
float z;
vec(float x=0, float y=0,float z=0):x(x), y(y),z(z){}
float& operator[](int idx){
return (idx==2)?z:(idx==1)?y:x;
}
float operator[](int idx) const{
return (idx==2)?z:(idx==1)?y:x;
}
};
There are some problems, though:
1) I don't know how you'd go around defining member functions without having to write them (or at least some sort of stub) more than once.
2) It relies on compiler optimizations. I looked at the output from g++ -O3 -S and it seems that the loop gets unrolled and the ?:s get replaced with the proper field accesses. The question is, would this still be handled properly in a real context, say within an algorithm?
A simple solution might be the best here:
struct Type
{
enum { x, y };
int values[2];
};
Type t;
if (t.values[0] == t.values[Type::x])
cout << "Good";
You can also do something like this:
struct Type
{
int values[2];
int x() const {
return values[0];
}
void x(int i) {
values[0] = i;
}
};
If you do not want to write it yourself, you may check some of the libraries suggested on:
C++ Vector Math and OpenGL compatable
If you use one specific compiler, you may use non standard methods, like packing information or nameless structs (Visual Studio):
union Vec3
{
struct {double x, y, z;};
double v[3];
};
On the other hand, casting several member variables to an array seems dangerous because the compiler may change the class layout.
So the logic solution seems to have one array and using methods to access that array. For example:
template<size_t D>
class Vec
{
private:
float data[D];
public: // Constants
static const size_t num_coords = D;
public: // Coordinate Accessors
float& x() { return data[0]; }
const float& x() const { return data[0]; }
float& y() { static_assert(D>1, "Invalid y()"); return data[1]; }
const float& y() const { static_assert(D>1, "Invalid y()"); return data[1]; }
float& z() { static_assert(D>2, "Invalid z()"); return data[2]; }
const float& z() const { static_assert(D>2, "Invalid z()"); return data[2]; }
public: // Vector accessors
float& operator[](size_t index) {return data[index];}
const float& operator[](size_t index) const {return data[index];}
public: // Constructor
Vec() {
memset(data, 0, sizeof(data));
}
public: // Explicit conversion
template<size_t D2>
explicit Vec(const Vec<D2> &other) {
memset(data, 0, sizeof(data));
memcpy(data, other.data, std::min(D, D2));
}
};
Using the above class, you may access the member array using the [] operator, coordinates using the accessor methods x(), y(), z(). Slicing is prevented using explicit conversion constructors. It disables the use of the accessors for lower dimensions using static_assert. If you are not using C++11, you may use Boost.StaticAssert
You can also templatized your methods. You can use for in order to extend them to N dimensions or use recursive calls. For example, in order to compute the square sum:
template<size_t D>
struct Detail
{
template<size_t C>
static float sqr_sum(const Vec<D> &v) {
return v[C]*v[C] + sqr_sum<C-1>(v);
}
template<>
static float sqr_sum<0>(const Vec<D> &v) {
return v[0]*v[0];
}
};
template<size_t D>
float sqr_sum(const Vec<D> &v) {
return Detail<D>::sqr_sum<D-1>(v);
}
The above code can be used:
int main()
{
Vec<3> a;
a.x() = 2;
a.y() = 3;
std::cout << a[0] << " " << a[1] << std::endl;
std::cout << sqr_sum(a) << std::endl;;
return 0;
}
In order to prevent template bloat, you may code your templated methods on a cpp and instantiated them for D=1, 2, 3, 4.
This is yet another approach. The following works on gcc C++11:
#include <stdio.h>
struct Vec4
{
union
{
float raw[4];
struct {
float x;
float y;
float z;
float w;
};
};
};
int main()
{
Vec4 v = { 1.f, 2.f, 3.f, 4.f };
printf("%.2f, %.2f, %.2f, %.2f\n", v.x, v.y, v.z, v.w);
printf("%.2f, %.2f, %.2f, %.2f\n", v.raw[0], v.raw[1], v.raw[2], v.raw[3]);
return 0;
}
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.