How can I access a struct property by string name? - c++

I have a struct:
typedef struct Tick {
double open;
double high;
double low;
double close;
double ema100;
} Tick;
I would like to access a property given a key:
Tick currentTick = {44.5, 45.1, 44.2, 44.6, 44.255};
std::string key = "ema100";
std::cout << currentTick[key];
Is there a way to do this without using std::map? I imagine the answer is no, but I just want to be certain before modifying everything to use std::map and increase my memory requirements.

Is there a way to do this without using std::map?
As long as you are willing to live with a series of cascading if-else statements, you can do that.
I would question the design though.
You can get there partially using tag based member variables. Sample working example:
#include <iostream>
struct OpenTag {};
struct HighTag {};
struct LowTag {};
struct CloseTag {};
struct Ema100Tag {};
struct Tick {
template <typename Tag> struct Member
{
double val;
operator double () const { return val; }
operator double& () { return val; }
};
struct AllMembers : Member<OpenTag>,
Member<HighTag>,
Member<LowTag>,
Member<CloseTag>,
Member<Ema100Tag> {};
AllMembers data;
template <typename Tag>
double operator[](Tag t) const
{
return (Member<Tag> const&)(data);
}
template <typename Tag>
double& operator[](Tag t)
{
return (Member<Tag>&)(data);
}
};
int main()
{
Tick t;
t[OpenTag()] = 12.345;
std::cout << t[OpenTag()] << std::endl;
}
Output:
12.345

The feature you're looking for is called reflection. This is not supported by native C++. You can either check for some 3rd-party libraries to do the reflection for you (but still would require lot of manual effort).
Or the other option is (as you mentioned) using std::map (or rather std::unordered_map as it would perform better) to map the name to id or offset (pointer) of the field within the class and then via switch statement (in former case) or directly using the pointer (in the latter case) modify the field value.

You can do that using metadata available at compile time. However, we must do it manually:
template<typename Class, typename T>
struct Property {
constexpr Property(T Class::*aMember, const char* aName) : member{aMember}, name{aName} {}
using Type = T;
T Class::*member;
const char* name;
};
template<typename Class, typename T>
constexpr auto makeProperty(T Class::*member, const char* name) {
return Property<Class, T>{member, name};
}
Now we have a class that can hold our desired metadata. Here's how to use it:
struct Dog {
constexpr static auto properties = std::make_tuple(
makeProperty(&Dog::barkType, "barkType"),
makeProperty(&Dog::color, "color")
);
private:
std::string barkType;
std::string color;
};
Now we can do iteration on it by recursion:
template<std::size_t iteration, typename T, typename U>
void accessGetByString(T&& object, std::string name, U&& access) {
// get the property
constexpr auto property = std::get<iteration>(std::decay_t<T>::properties);
if (name == property.name) {
std::forward<U>(access)(std::forward<T>(object).*(property.member));
}
}
template<std::size_t iteration, typename T, typename U>
std::enable_if_t<(iteration > 0)>
getByStringIteration(T&& object, std::string name, U&& access) {
accessGetByString<iteration>(std::forward<T>(object), name, std::forward<U>(access));
// next iteration
getByStringIteration<iteration - 1>(std::forward<T>(object), name, std::forward<U>(access));
}
template<std::size_t iteration, typename T, typename U>
std::enable_if_t<(iteration == 0)>
getByStringIteration(T&& object, std::string name, U&& access) {
accessGetByString<iteration>(std::forward<T>(object), name, std::forward<U>(access));
}
template<typename T, typename U>
void getByString(T&& object, std::string name, U&& access) {
getByStringIteration<std::tuple_size<decltype(std::decay_t<T>::properties)>::value - 1>(
std::forward<T>(object),
name,
std::forward<U>(access)
);
}
Then finally, you can use this tool like:
struct MyAccess {
void operator()(int i) { cout << "got int " << i << endl; }
void operator()(double f) { cout << "got double " << f << endl; }
void operator()(std::string s) { cout << "got string " << s << endl; }
}
Dog myDog;
getByString(myDog, "color", MyAccess{});
This for sure could by simplified with overloaded lambda. To know more about overloaded lambda, see this blog post
The original code was taken from that answer: C++ JSON Serialization
There's a proposal to make things like this easier.
This is covered by P0255r0

Honestly i think the use of an overloaded operator[] and if-else statement is all you really need. Given any class, are their really that many members? The other solutions in my opinion provide too much overhead for such a simple task. I would just do something like this:
template <typename T>
T& operator[](const std::string& key)
{
if (key == ...)
// do something
}

Related

Dynamically iterate over static information

Suppose I have some class specialized for each enum type:
enum MyEnum {
EnumA = 0, EnumB, EnumSize
};
template <enum MyEnum>
class StaticEnumInfo {
};
template <>
class StaticEnumInfo<EnumA>{
typedef bool type;
const std::string name = "EnumA";
};
template <>
class StaticEnumInfo<EnumB>{
typedef int type;
const std::string name = "EnumB";
};
Is it possible to iterate over all names and print them?
I want to write something like:
for(MyEnum i = EnumA; i < EnumSize; ++i){
// Doesn't make sense, I know.
std::cout << StaticEnumInfo<i>::name << std::endl;
}
I know I can create one map somewhere else to solve this kind of mapping (for the strings, not the types...)
I don't have access to boost
Until proper expansion statements are available, you could always do this:
template <typename T, T... S, typename F>
constexpr void for_sequence(std::integer_sequence<T, S...>, F&& f) {
(static_cast<void>(f(std::integral_constant<T, S>{})), ...);
}
And use it like this:
for_sequence(
std::make_integer_sequence<int, EnumSize>{},
[&](auto i) {
constexpr auto index = static_cast<MyEnum>(int{i});
std::cout << StaticEnumInfo<index>::name << std::endl;
}
);
However be careful, as it will only work if all enum member are sequential.
Live example

Type Erasure for objects containing a std::tuple in c++11

Lets say I have a generic class Container that contains any type of tuple, and has a function template<typename T> T& get<T>(); that returns a reference to the element in the tuple. My very simple implementation looks like this:
template<typename... Ts>
class Container
{
std::tuple<Ts...> contents;
public:
Container(const Ts&... ts) : contents(ts...) {}
template <typename T>
T& get()
{
//TypeIndex is some meta-programming struct to find index of T in Ts
return std::get<TypeIndex<T, Ts...>::value>(contents);
}
};
Are there any good type erasure techniques to turn Container into a regular class without altering the get function signature? As in calling get<T>() without knowing the tuples full type list? Something like this:
Struct A { int x; }
Struct B { int y; }
Struct C { int z; }
int main()
{
Container container(A(), B()); //Underlying storage is a std::tuple<A, B>
A& a = container.get<A>(); //Doesn't know the tuples type list but assumes A is in there.
C& c = container.get<C>(); //C isn't in the tuples type list, crash program, which would be correct behavior.
}
boost::any is the usual go-to solution for these types of problems, but doesn't solve this particular problem because I would have to know the actual type of the underlying tuple to cast. Like if I tried to use it in the example above I would do boost::any_cast<std::tuple<A, B>> to get A, or B which isn't any use to me because I'm purposely trying to hide the tuple type list.
Edit: full definition of TypeIndex.
#include <type_traits>
template <typename T, typename... Ts>
struct TypeIndex;
template <typename T, typename... Ts>
struct TypeIndex<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename U, typename... Ts>
struct TypeIndex<T, U, Ts...> : std::integral_constant<std::size_t, 1 + TypeIndex<T, Ts...>::value> {};
Instead of hand written TypeIndex<T, Ts...>::value you can use typeid(T)::hash_code() and store data in a std::unordered_map<size_t, boost::any>.
std::tuple does not store information about underlying types. That information is encoded in tuple's type. So if your get method can't know the type of the tuple, then it can't get offset in it where the value is stored. So you have to revert to dynamic methods and having a map is the simpliest one.
A slightly more efficient solution than the ones proposed so far is to use std::tuple as the actual underlying storage, thus avoiding use of any or unordered_map
If we use the classic type-erasure pattern, we only need one dynamic allocation (plus whatever is required to copy the actual objects), or zero if you implement small buffer optimization.
We start by defining a base interface to access an element by type.
struct base
{
virtual ~base() {}
virtual void * get( std::type_info const & ) = 0;
};
We use void* instead of any to return a reference to the object, thus avoiding a copy and possibly a memory allocation.
The actual storage class is derived from base, and templated on the arguments it can contain:
template<class ... Ts>
struct impl : base
{
template<class ... Us>
impl(Us && ... us) : data_(std::forward<Us>(us) ... )
{
//Maybe check for duplicated types and throw.
}
virtual void * get( std::type_info const & ti )
{
return get_helper( ti, std::index_sequence_for<Ts...>() );
}
template<std::size_t ... Indices>
void* get_helper( std::type_info const & ti, std::index_sequence<Indices...> )
{
//If you know that only one element of a certain type is available, you can refactor this to avoid comparing all the type_infos
const bool valid[] = { (ti == typeid(Ts)) ... };
const std::size_t c = std::count( std::begin(valid), std::end(valid), true );
if ( c != 1 )
{
throw std::runtime_error(""); // something here
}
// Pack the addresses of all the elements in an array
void * result[] = { static_cast<void*>(& std::get<Indices>(data_) ) ... };
// Get the index of the element we want
const int which = std::find( std::begin(valid), std::end(valid), true ) - std::begin(valid);
return result[which];
}
std::tuple<Ts ... > data_;
};
Now we only have to wrap this in a type-safe wrapper:
class any_tuple
{
public:
any_tuple() = default; // allow empty state
template<class ... Us>
any_tuple(Us && ... us) :
m_( new impl< std::remove_reference_t< std::remove_cv_t<Us> > ... >( std::forward<Us>(us) ... ) )
{}
template<class T>
T& get()
{
if ( !m_ )
{
throw std::runtime_error(""); // something
}
return *reinterpret_cast<T*>( m_->get( typeid(T) ) );
}
template<class T>
const T& get() const
{
return const_cast<any_tuple&>(*this).get<T>();
}
bool valid() const { return bool(m_); }
private:
std::unique_ptr< base > m_; //Possibly use small buffer optimization
};
Check it live.
This can be extended further in many ways, for instance you can add a constructor that takes an actual tuple, you can access by index and pack the value in a std::any, etc.
#include <iostream>
struct tuple_base {
virtual ~tuple_base() {}
};
template <typename T>
struct leaf : virtual tuple_base {
leaf(T const & t) : value(t) {}
virtual ~leaf() {}
T value;
};
template <typename ... T>
struct tuple : public leaf<T> ... {
template <typename ... U>
tuple(U && ... u) : leaf<T>{static_cast<U&&>(u)} ... {}
};
struct container {
tuple_base* erased_value;
template <typename T>
T & get() {
return dynamic_cast<leaf<T>*>(erased_value)->value;
}
};
int main() {
container c{new tuple<int, float, char>{1, 1.23f, 'c'}};
std::cout << c.get<float>() << std::endl;
}
The key is that you must know more information about the structure of the tuple type. It is not possible to extract information from a type erased arbitrary tuple implementation using only a single type which it contains. This is more of a proof of concept, and you would probably be better off using something else, though it is the solution to what you asked.
If you're ok with using boost::any, you could use a vector or unordered_map of them. Here's a version implemented with unordered_map:
class Container
{
public:
template<typename... Ts>
Container(std::tuple<Ts...>&& t)
{
tuple_assign(std::move(t), data, std::index_sequence_for<Ts...>{});
}
template<typename T>
T get()
{
auto it = data.find(typeid(T));
if(it == data.cend()) {
throw boost::bad_any_cast{};
} else {
return boost::any_cast<T>(it->second);
}
}
private:
std::unordered_map<std::type_index, boost::any> data;
};
And then you could write almost as in your request. I changed the constructor to accept a tuple to avoid a host of sfinae code to prevent overridding copy/move constructors, but you can do this if you so wish.
Container c(std::make_tuple(1, 1.5, A{42}));
try {
std::cout << "int: " << c.get<int>() << '\n';
std::cout << "double: " << c.get<double>() << '\n';
std::cout << "A: " << c.get<A>().val << '\n';
c.get<A&>().val = 0;
std::cout << "A: " << c.get<A>().val << '\n';
std::cout << "B: " << c.get<B>().val << '\n'; // error
} catch (boost::bad_any_cast const& ex) {
std::cout << "exception: " << ex.what() << '\n';
}
live demo
You could also instruct your Container to commit std::terminate() instead of throwing an exception.

Generating one class member per variadic template argument

I have a template class where each template argument stands for one type of value the internal computation can handle. Templates (instead of function overloading) are needed because the values are passed as boost::any and their types are not clear before runtime.
To properly cast to the correct types, I would like to have a member list for each variadic argument type, something like this:
template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2>
class MyClass {
std::vector<T1> m_argumentsOfType1;
std::vector<T2> m_argumentsOfType2; // ...
};
Or alternatively, I'd like to store the template argument types in a list, as to do some RTTI magic with it (?). But how to save them in a std::initializer_list member is also unclear to me.
Thanks for any help!
As you have already been hinted, the best way is to use a tuple:
template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2>
class MyClass {
std::tuple<std::vector<AcceptedTypes>...> vectors;
};
This is the only way to multiply the "fields" because you cannot magically make it spell up the field names. Another important thing may be to get some named access to them. I guess that what you're trying to achieve is to have multiple vectors with unique types, so you can have the following facility to "search" for the correct vector by its value type:
template <class T1, class T2>
struct SameType
{
static const bool value = false;
};
template<class T>
struct SameType<T, T>
{
static const bool value = true;
};
template <typename... Types>
class MyClass
{
public:
typedef std::tuple<vector<Types>...> vtype;
vtype vectors;
template<int N, typename T>
struct VectorOfType: SameType<T,
typename std::tuple_element<N, vtype>::type::value_type>
{ };
template <int N, class T, class Tuple,
bool Match = false> // this =false is only for clarity
struct MatchingField
{
static vector<T>& get(Tuple& tp)
{
// The "non-matching" version
return MatchingField<N+1, T, Tuple,
VectorOfType<N+1, T>::value>::get(tp);
}
};
template <int N, class T, class Tuple>
struct MatchingField<N, T, Tuple, true>
{
static vector<T>& get(Tuple& tp)
{
return std::get<N>(tp);
}
};
template <typename T>
vector<T>& access()
{
return MatchingField<0, T, vtype,
VectorOfType<0, T>::value>::get(vectors);
}
};
Here is the testcase so you can try it out:
int main( int argc, char** argv )
{
int twelf = 12.5;
typedef reference_wrapper<int> rint;
MyClass<float, rint> mc;
vector<rint>& i = mc.access<rint>();
i.push_back(twelf);
mc.access<float>().push_back(10.5);
cout << "Test:\n";
cout << "floats: " << mc.access<float>()[0] << endl;
cout << "ints: " << mc.access<rint>()[0] << endl;
//mc.access<double>();
return 0;
}
If you use any type that is not in the list of types you passed to specialize MyClass (see this commented-out access for double), you'll get a compile error, not too readable, but gcc at least points the correct place that has caused the problem and at least such an error message suggests the correct cause of the problem - here, for example, if you tried to do mc.access<double>():
error: ‘value’ is not a member of ‘MyClass<float, int>::VectorOfType<2, double>’
An alternate solution that doesn't use tuples is to use CRTP to create a class hierarchy where each base class is a specialization for one of the types:
#include <iostream>
#include <string>
template<class L, class... R> class My_class;
template<class L>
class My_class<L>
{
public:
protected:
L get()
{
return val;
}
void set(const L new_val)
{
val = new_val;
}
private:
L val;
};
template<class L, class... R>
class My_class : public My_class<L>, public My_class<R...>
{
public:
template<class T>
T Get()
{
return this->My_class<T>::get();
}
template<class T>
void Set(const T new_val)
{
this->My_class<T>::set(new_val);
}
};
int main(int, char**)
{
My_class<int, double, std::string> c;
c.Set<int>(4);
c.Set<double>(12.5);
c.Set<std::string>("Hello World");
std::cout << "int: " << c.Get<int>() << "\n";
std::cout << "double: " << c.Get<double>() << "\n";
std::cout << "string: " << c.Get<std::string>() << std::endl;
return 0;
}
One way to do such a thing, as mentioned in πάντα-ῥεῖ's comment is to use a tuple. What he didn't explain (probably to save you from yourself) is how that might look.
Here is an example:
using namespace std;
// define the abomination
template<typename...Types>
struct thing
{
thing(std::vector<Types>... args)
: _x { std::move(args)... }
{}
void print()
{
do_print_vectors(std::index_sequence_for<Types...>());
}
private:
template<std::size_t... Is>
void do_print_vectors(std::index_sequence<Is...>)
{
using swallow = int[];
(void)swallow{0, (print_one(std::get<Is>(_x)), 0)...};
}
template<class Vector>
void print_one(const Vector& v)
{
copy(begin(v), end(v), ostream_iterator<typename Vector::value_type>(cout, ","));
cout << endl;
}
private:
tuple<std::vector<Types>...> _x;
};
// test it
BOOST_AUTO_TEST_CASE(play_tuples)
{
thing<int, double, string> t {
{ 1, 2, 3, },
{ 1.1, 2.2, 3.3 },
{ "one"s, "two"s, "three"s }
};
t.print();
}
expected output:
1,2,3,
1.1,2.2,3.3,
one,two,three,
There is a proposal to allow this kind of expansion, with the intuitive syntax: P1858R1 Generalized pack declaration and usage. You can also initialize the members and access them by index. You can even support structured bindings by writing using... tuple_element = /*...*/:
template <typename... Ts>
class MyClass {
std::vector<Ts>... elems;
public:
using... tuple_element = std::vector<Ts>;
MyClass() = default;
explicit MyClass(std::vector<Ts>... args) noexcept
: elems(std::move(args))...
{
}
template <std::size_t I>
requires I < sizeof...(Ts)
auto& get() noexcept
{
return elems...[I];
}
template <std::size_t I>
requires I < sizeof...(Ts)
const auto& get() const
{
return elems...[I];
}
// ...
};
Then the class can be used like this:
using Vecs = MyClass<int, double>;
Vecs vecs{};
vecs.[0].resize(3, 42);
std::array<double, 4> arr{1.0, 2.0, 4.0, 8.0};
vecs.[1] = {arr.[:]};
// print the elements
// note the use of vecs.[:] and Vecs::[:]
(std::copy(vecs.[:].begin(), vecs.[:].end(),
std::ostream_iterator<Vecs::[:]>{std::cout, ' '},
std::cout << '\n'), ...);
Here is a less than perfectly efficient implementation using boost::variant:
template<typename ... Ts>
using variant_vector = boost::variant< std::vector<Ts>... >;
template<typename ...Ts>
struct MyClass {
using var_vec = variant_vector<Ts...>;
std::array<var_vec, sizeof...(Ts)> vecs;
};
we create a variant-vector that can hold one of a list of types in it. You have to use boost::variant to get at the contents (which means knowing the type of the contents, or writing a visitor).
We then store an array of these variant vectors, one per type.
Now, if your class only ever holds one type of data, you can do away with the array, and just have one member of type var_vec.
I cannot see why you'd want one vector of each type. I could see wanting a vector where each element is one of any type. That would be a vector<variant<Ts...>>, as opposed to the above variant<vector<Ts>...>.
variant<Ts...> is the boost union-with-type. any is the boost smart-void*. optional is the boost there-or-not.
template<class...Ts>
boost::optional<boost::variant<Ts...>> to_variant( boost::any );
may be a useful function, that takes an any and tries to convert it to any of the Ts... types in the variant, and returns it if it succeeds (and returns an empty optional if not).

Detecting a function in C++ at compile time

Is there a way, presumably using templates, macros or a combination of the two, that I can generically apply a function to different classes of objects but have them respond in different ways if they do not have a specific function?
I specifically want to apply a function which will output the size of the object (i.e. the number of objects in a collection) if the object has that function but will output a simple replacement (such as "N/A") if the object doesn't. I.e.
NO_OF_ELEMENTS( mySTLMap ) -----> [ calls mySTLMap.size() to give ] ------> 10
NO_OF_ELEMENTS( myNoSizeObj ) --> [ applies compile time logic to give ] -> "N/A"
I expect that this might be something similar to a static assertion although I'd clearly want to compile a different code path rather than fail at build stage.
From what I understand, you want to have a generic test to see if a class has a certain member function. This can be accomplished in C++ using SFINAE. In C++11 it's pretty simple, since you can use decltype:
template <typename T>
struct has_size {
private:
template <typename U>
static decltype(std::declval<U>().size(), void(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
public:
typedef decltype(test<T>(0)) type;
enum { value = type::value };
};
If you use C++03 it is a bit harder due to the lack of decltype, so you have to abuse sizeof instead:
template <typename T>
struct has_size {
private:
struct yes { int x; };
struct no {yes x[4]; };
template <typename U>
static typename boost::enable_if_c<sizeof(static_cast<U*>(0)->size(), void(), int()) == sizeof(int), yes>::type test(int);
template <typename>
static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
Of course this uses Boost.Enable_If, which might be an unwanted (and unnecessary) dependency. However writing enable_if yourself is dead simple:
template<bool Cond, typename T> enable_if;
template<typename T> enable_if<true, T> { typedef T type; };
In both cases the method signature test<U>(int) is only visible, if U has a size method, since otherwise evaluating either the decltype or the sizeof (depending on which version you use) will fail, which will then remove the method from consideration (due to SFINAE. The lengthy expressions std::declval<U>().size(), void(), std::true_type() is an abuse of C++ comma operator, which will return the last expression from the comma-separated list, so this makes sure the type is known as std::true_type for the C++11 variant (and the sizeof evaluates int for the C++03 variant). The void() in the middle is only there to make sure there are no strange overloads of the comma operator interfering with the evaluation.
Of course this will return true if T has a size method which is callable without arguments, but gives no guarantees about the return value. I assume wou probably want to detect only those methods which don't return void. This can be easily accomplished with a slight modification of the test(int) method:
// C++11
template <typename U>
static typename std::enable_if<!is_void<decltype(std::declval<U>().size())>::value, std::true_type>::type test(int);
//C++03
template <typename U>
static typename std::enable_if<boost::enable_if_c<sizeof(static_cast<U*>(0)->size()) != sizeof(void()), yes>::type test(int);
There was a discussion about the abilities of constexpr some times ago. It's time to use it I think :)
It is easy to design a trait with constexpr and decltype:
template <typename T>
constexpr decltype(std::declval<T>().size(), true) has_size(int) { return true; }
template <typename T>
constexpr bool has_size(...) { return false; }
So easy in fact that the trait loses most of its value:
#include <iostream>
#include <vector>
template <typename T>
auto print_size(T const& t) -> decltype(t.size(), void()) {
std::cout << t.size() << "\n";
}
void print_size(...) { std::cout << "N/A\n"; }
int main() {
print_size(std::vector<int>{1, 2, 3});
print_size(1);
}
In action:
3
N/A
This can be done using a technique called SFINAE. In your specific case you could implement that using Boost.Concept Check. You'd have to write your own concept for checking for a size-method. Alternatively you could use an existing concept such as Container, which, among others, requires a size-method.
You can do something like
template< typename T>
int getSize(const T& t)
{
return -1;
}
template< typename T>
int getSize( const std::vector<T>& t)
{
return t.size();
}
template< typename T , typename U>
int getSize( const std::map<T,U>& t)
{
return t.size();
}
//Implement this interface for
//other objects
class ISupportsGetSize
{
public:
virtual int size() const= 0;
};
int getSize( const ISupportsGetSize & t )
{
return t.size();
}
int main()
{
int s = getSize( 4 );
std::vector<int> v;
s = getSize( v );
return 0;
}
basically the most generic implementation is always return -1 or "NA" but for vector and maps it will return the size. As the most general one always matches there is never a build time failure
Here you go. Replace std::cout with the output of your liking.
template <typename T>
class has_size
{
template <typename C> static char test( typeof(&C::size) ) ;
template <typename C> static long test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
template<bool T>
struct outputter
{
template< typename C >
static void output( const C& object )
{
std::cout << object.size();
}
};
template<>
struct outputter<false>
{
template< typename C >
static void output( const C& )
{
std::cout << "N/A";
}
};
template<typename T>
void NO_OF_ELEMENTS( const T &object )
{
outputter< has_size<T>::value >::output( object );
}
You could try something like:
#include <iostream>
#include <vector>
template<typename T>
struct has_size
{
typedef char one;
typedef struct { char a[2]; } two;
template<typename Sig>
struct select
{
};
template<typename U>
static one check (U*, select<char (&)[((&U::size)!=0)]>* const = 0);
static two check (...);
static bool const value = sizeof (one) == sizeof (check (static_cast<T*> (0)));
};
struct A{ };
int main ( )
{
std::cout << has_size<int>::value << "\n";
std::cout << has_size<A>::value << "\n";
std::cout << has_size<std::vector<int>>::value << "\n";
}
but you have to be careful, this does neither work when size is overloaded, nor when it is a template. When you can use C++11, you can replace the above sizeof trick by decltype magic

C++ replacing member variables with values from other types

I have a class T with n member variables, for example
class T{
ushort name;
ushort id;
double value;
.....etc...
};
I also have a collection of classes T1, T2...., each consisting of member variables
which are subsets of member variables of T (for lack of a better word, let me call
this a subset type of T). For example, T1 may be
class T1 {
ushort name;
double value;
};
which just picks up two members of T.
I would like to write a method
template <typename X>
T join(T t, X x)
where we return a class of type T, by replacing values of each member variable in t, with
those of x (provided X is a sub-type of T) and the other values of t remain the same.
I can think of doing this via specializations. But there should be an elegant method of doing this (perhaps detecting when a type X is a subset-type of T and doing the right thing).
I can think of doing this via specializations. But there should be an elegant method of doing this (perhaps detecting when a type X is a subset-type of T and doing the right thing).
"Detecting" is part of specialization. You should provide specializations for "subset"-types and provide no implementation for generic specialization (to provoke compilation error, when someone uses other types with that method).
If you don't want to provide specializations for all subset types. You can try to use the member detector idiom: Member Detector, or __if_exist if you are using MSVC.
So you only need to write [number of members in T] * 2 macros(and if use MSVC, you don't need the SetXXX) instead of specializing all possible combinations of members in T
CREATE_MEMBER_DETECTOR(name);
CREATE_MEMBER_DETECTOR(id);
CREATE_MEMBER_DETECTOR(value);
......
template<int N, typename T, typename R>
class SetName
{
public:
void operator()(T& t, R& r)
{
}
};
template<typename T, typename R>
class SetName<1, T, R>
{
public:
void operator()(T& t, R& r)
{
t.name = r.name;
}
};
......
(can be macros too)
And the join() should be:
template <typename SUBSET>
T join(T t, SUBSET x)
{
SetName<Detect_name<SUBSET>::value, T, SUBSET>()(t, x);
SetValue<Detect_value<SUBSET>::value, T, SUBSET>()(t, x);
......
return t;
}
I would implement conversion from T1...Tn to T (or some class that is derived from T and has info which members are actually set), and then implement join() function in terms of T. Don't think this is good place for template magic actually
Try this:
#include <iostream>
#include <typeifo>
using namespace std;
template<typename T>
struct SetBase
{
T first;
T second;
SetBase(const T& first = T(), const T& second = T())
: first(first), second(second) {}
};
template<typename T>
struct Set : public SetBase<T>
{
short name_id;
Set(const T& first = T(), const T& second = T(), const short& name) :
SetBase<T>(first, second), name_id(name){}
};
template<typename Class, typename BaseClass>
Class* join(Class **a, BaseClass *b)
{
if(typeid(Class) != typeid(BaseClass))
{
Class* retval = new Class(*static_cast<Class*>(b));
retval->name_id = (*a)->name_id;
*a = retval;
}
else
{
Class* retval = new Class(*b);
*a = retval;
}
return retval;
}
int main()
{
Set<int> *a = new Set<int>(1, 2, 3);
SetBase<int> *b = new SetBase<int>(4, 5);
cout << join(&a, b)->first << " " << join(&a, b)->second << " " << join(&a, b)->name_id << "\n";
cout << a->first << " " << a->second << " " << a->name_id << "\n";
return 0;
}
The Set class is public derived from SetBase, so the cast that I use is valid