Variadic Template + static array - c++11

Here we go, I got a template class with variadic classes arguments, each class has its own id from an enum value, for example:
struct A
{
enum ETypeID
{
Value = 244
};
};
(same pattern for some other classes)
now I got :
template<typename TypeList...>
struct TClass
{
static int _IDs[sizeof(TypeList)...];
};
I can't figure out how to feed the static array with each ETypeID::Value from the given typelist.
Any help would greatly be appreciated

template<typename... TypeList>
struct TClass
{
constexpr static int _IDs[sizeof...(TypeList)] = {TypeList::Value...};
};
live example on wandbox
constexpr is required for in-place static data member initialization
sizeof...(TypeList) evaluates to the number of elements in the TypeList... pack
For TypeList = {A, B, C}, TypeList::Value... expands to: A::Value, B::Value, C::Value

Related

Compile time existence checking for a member function with signature fit to variadic parameters pack

I would like to check if there exist a member function with signature fit to a parameter pack. I began with the known SFINAE concept, while trying to extend it for considering also a parameters pack. But at this point I found that I don't know how to do it.
I try to do something like this:
// Note: T object may have several functions with the name foo, but with different signatures.
// a function foo also can be a template one with variadic parameters pack.
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
template<typename U>
static bool test(decltype(&U::foo));
template<typename U>
static float test(...);
public:
static constexpr bool value = std::is_integral<decltype(test<T>(Args...))>::value;
//-------------------------------------------------------------^^^^^^^^^
// how to do it?
};
I would like to use it for declaring specific object at compile time - something like this:
class Bar
{
public:
template<typename T, typename...Args>
void doSomthing(T* p, Args&&...parameters)
{
// get correct object type:
// if T has a function called foo with parameters fits for pack, then declare A, o.w declare B.
using ObjType = typename std::conditional<HAS_FUNCTION_FOO<T, Args>::value, A, B>::type;
// compute
ObjType::doSomthing(p, std::forward<Args>(parameters)...);
}
private:
struct A
{
template<typename T, typename...Args>
static void doSomthing(T* p, Args&&...parameters)
{
p->foo(std::forward<Args>(parameters)...);
}
};
struct B
{
template<typename T, typename...Args>
static void doSomthing(T* p, Args&&...parameters)
{
// do something else
}
};
};
Something like this, perhaps:
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
template <typename U>
static std::true_type test(
typename std::enable_if<sizeof(
decltype(std::declval<U>().foo(std::declval<Args>()...))*) != 0>::type*
);
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(nullptr))::value;
};
Demo

Store parameter pack as tuple references

I am trying to store the parameter pack of lvalue references of a variadic template for later use.
I have the following working for now.
template <typename... Ts>
class Foo {
private:
std::tuple<Ts...> m_args;
public:
template<typename... Args>
Foo(Args&&... args) : m_args(std::make_tuple(std::forward<Args>(args)...))
{
}
};
int main() {
int x = 10;
int y = 20;
Foo<int, int> foo(x, y);
}
However, I would like to store the parameter pack as a reference so that I can access the same object later.
I am not sure how I can do that. Any help would be appreciated.
The best I can imagine, is the use of std::forward_as_tuple.
Unfortunately I don't see a way to use it with perfect forwarding: if you want register values in a tuple inside a class, you have to decide the type of the tuple one time for all.
The best I can imagine is a tuple of const references; something as follows
template <typename ... Ts>
class Foo
{
private:
std::tuple<Ts const & ...> m_args;
public:
Foo (Ts const & ... as) : m_args{std::forward_as_tuple(as...)}
{ }
};
I hope isn't necessary remember you how dangling references can be dangerous for a solution based on a tuple of references.

Idiom for default initialization depending on type

I have a template class that takes default member values.
template<class T = std::string>
struct A{
T val = {"val"};
};
However sometimes the default values do not make sense, for example:
A<int> a1; // cannot initialize int from "val"
Is there is good idiom to handle this issue?
I came up with this solution, which is quite verbose.
template<class T, class TT>
auto valid_or_default(TT&& other) ->
decltype(T{std::forward<TT>(other)}){return T{std::forward<TT>(other)};}
template<class T>
auto value_of_default(...){return T{};}
template<class T = std::string>
struct A{
T val = valid_or_default<T>("val");
};
(The other option is to set up a Boost.Fusion map to have a default value per type, but it is even more code and all the cases need to be handled.)
Update (thanks #Someprogrammerdude):
Another alternative for very specific cases (no valid based on syntax) can be done by specializing the constructor:
template<class T = std::string>
struct A{
T val;// = valid_or_default<T>("val");
A() : val{}{}
};
template<> A<std::string>::A() : val{"val"}{}
I still don't know what the original problem you try to solve is, or why you need to use a compile-time fixed-value for the initialization, but as it seems your structure is an aggregate you could simply use aggregate initialization:
template<typename T = std::string>
struct A
{
T val;
};
// ...
A a = { "val" };
A<int> b = { 1 };
Here is a C++17 solution:
template<class T, class TT>
auto valid_or_default(TT&& other)
{
if constexpr (std::is_constructible_v<T, TT>)
return T{std::forward<TT>(other)};
else
return T{};
}
Here's another option.
template <typename T>
T get_default_value()
{
return {};
}
template <>
std::string get_default_value<std::string>()
{
return "val";
}
template<class T = std::string>
struct A {
T val = get_default_value<T>();
};

Pointers to member as variadic template parameters

Is it possible to pass pointers-to-member as variadic template arguments. I can't seem to figure out the syntax.
for a function call it works like this:
struct A
{
int a;
float b;
}
template <typename ... TArgs> void f(A *obj, TArgs ... params)
{
void *members[] { (&(obj->*params))... };
// ... do something ...
}
That can be used like this:
f(obj, &A::a, &A::b);
I would like to pass params in a similar fashion to a class template
template <[something] ... params> class Foo
{
void Bar(A *obj)
{
void *members[] { (&(obj->*params))... };
// ... do something ...
}
};
That should be used like this:
Foo<&A::a, &A::b> foo;
foo.bar(obj);
I'm having trouble figuring out what [something] should be.
If member type is known and there is only one parameter, it can be done like this:
template <int A::*ptr> //...
Is there a way to generalize this for variadic parameter list of member pointers where members are of different unknown beforehand types?
Update: Variadic argument pack for member pointers of fixed known types is declared like so:
template<int A::*...ptr> struct Foo {};
Now I just need to replace int with typename that can be deduced.
And with C++17, following works perfectly:
template<auto A::*...ptr> struct Foo {};
Unfortunately I need a solution that will work with C++14
In C++14, you can use another level of indirection to do that:
struct A {
int a;
float b;
};
template<typename... T>
struct Bar {
template <T A::*... params>
struct Foo {
void Bar(A *obj) {
void *members[] { (&(obj->*params))... };
// ... do something ...
(void)members;
}
};
};
int main() {
A a;
Bar<int, float>::Foo<&A::a, &A::b> foo;
foo.Bar(&a);
}
auto keyword (introduced with the C++17 for non-type template parameters, as you mentioned) solves more or less this kind of issues. Think of std::integral_constant and how would it be more user-friendly if you hadn't to specify each time the type as the first argument...

Migrating from VS to GCC: change in use of typename?

I'm building a large project on Debian 6.0.6 (with gcc 4.4.5) that was initially built in Microsoft VS (2008, I think).
What seems to be the problem is that when I declare a member as
typedef typename std::set<T>::iterator iterator, and then later use this iterator, gcc appears to interpret this as (const T*).
The part of the class containing the typename designation:
template <class entityType>
class entityArray
{
private: std::set<entityType> m_array;
public: typedef typename std::set<entityType>::iterator iterator;
...
public:
entityType* At( const char* name);
...
};
plus a few other classes that are needed for the discussion:
class entity
{
private:
entity* m_parent;
int m_ncid;
std::string m_name;
public:
entity () { m_ncid = 0; m_parent = NULL;}
virtual ~entity () {};
...
};
class attribute : public entity
{
public:
attribute(){};
virtual ~attribute(){};
};
class var : public entity
{
private:
entityArray<attribute> m_atts;
public:
var(){}
virtual ~var(){}
...
};
class dim : public entity
{
public:
dim() {};
virtual ~dim() {};
};
class group : public entity
{
private:
entityArray<var> m_vars;
entityArray<dim> m_dims;
...
public:
dim* DimAt( const char* dimname ) { return m_dims.At(dimname);}
};
Now an iterator is initialized through a call to the function DimAt which in turn calls At. The At function in the first class is defined as:
template <class entityType>
entityType* entityArray<entityType>::At( const char* name )
{
entityType dummy;
iterator iter;
entityType* ptr;
... define dummy ...
iter = m_array.find( dummy );
ptr = (iter != m_array.end()) ? &(*iter) : NULL;
return ptr;
}
Compiling the above produces
error: invalid conversion from const dim* to dim*., referring to &(*iter).
I realize that typename is required for declaring iterator, since the type is a dependent and qualified name, but I don't see why this substitution (const *) is being performed by the compiler. I would appreciate any help that you could provide. Thanks!
This has absolutely nothing to do with typename.
The standard allows std::set<T>::iterator and std::set<T>::const_iterator to be the same type, and with GCC the types are the same.
The reason is that modifying an element of a std::set e.g. by *iter = val might invalidate the ordering of the set elements, breaking the invariant that the elements of the set are always in order. By making the iterator type a constant iterator instead of a mutable iterator it's not possible to alter the element, preventing you from corrupting the set's ordering.
So with GCC's implementation, when you dereference the iterator using *iter you get a const entitType& and when you take its address using &*iter you get a const entityType*

Resources