Consider a template class C with a policy set via template template parameter and two policy definitions:
template<class T> struct PolicyOne { };
template<class T, int U, int V> struct PolicyTwo { };
template<class T, template<class> class POLICY> struct C { POLICY<T> policy; };
void f()
{
C<int, PolicyOne> mc1;
C<int, PolicyTwo<1, 2> > mc2; // doesn't work this way
}
PolicyTwo doesn't work because of wrong number of template arguments.
Is there a way to use PolicyTwo as POLICY template parameter if you specify the types for the additional template parameters?
I'm using C++03, so alias declarations are not available.
I'm aware of this question, but I don't see a solution to my problem there.
Depending on how the policy is used, you may be able to manage with inheritance in place of alias templates:
template<int U, int V> struct PolicyTwoAdaptor {
template<class T> struct type: PolicyTwo<T, U, V> { }; };
C<int, PolicyTwoAdaptor<1, 2>::type> mc2;
I can't see hwo to solve this with your current mechanism, but you can reverse the way it works and it should compile fine (and even may reduce complexity by removing the class template parameter):
template <typename T> struct PolicyBase { typedef T value_type; };
template<class T> struct PolicyOne : public PolicyBase<T> { };
template<class T, int U, int V> struct PolicyTwo : public PolicyBase<T> { };
template<class POLICY> struct C { POLICY policy; typedef typename POLICY::value_type T; };
void f()
{
C<PolicyOne<int> > mc1;
C<PolicyTwo<int, 1, 2> > mc2; // doesn't work this way
}
The basic idea is to move the type tempalte parameter out of the policy user, and give a fully instantiated policy to it instead. Then the policy provides its template type back to the policy user through a typedef (if needed).
Related
I have a class that can accept arithmetic types and std::complex. A simplified code of the class is
#include <complex>
template<typename T> struct is_complex : std::false_type {};
template<typename T> struct is_complex<std::complex<T>> : std::true_type {};
template<class T>
struct Foo {
void foo(typename T::value_type t)
requires (is_complex<T>::value) {
}
};
Now, I would like to take the internal type of std::complex and use it as the type of the parameters in the foo function.For example, if T is std::complex<double>, then I want the parameter types to be double.
This function should only be available when T is indeed std::complex.
I thought I could use typename T::value_type as the parameter type, since std::complex has a typedef value_type. Plus, I thought using requires here would avoid T to be substitued in this function in case T wasn't std::complex. Silly me.
The issue is that whenever I create a Foo<FundamentalType> the code breaks, since fundamentals don't have ::value_type.
int main() {
Foo<int> obj; // Breaks the code.
//obj.foo(4); // Function shouldn't be considered in overload resolution ideally...
Foo<std::complex<int>> obj2; // Works
obj2.foo(4); // Works as expected
}
Ideally, I would like the substitution of T to be ignored for this function in case T is not std::complex. Is that possible? If not, how can I circumvent this?
You're on the right track with is_complex: you'd like the same here, but with a different body of the type. For example,
template<typename T> struct complex_value_type {};
template<typename T> struct complex_value_type<std::complex<T>> { using type = T; };
template<typename T>
using complex_value_type_t = typename complex_value_type<T>::type;
Then, at any point, you can call it as complex_value_type_t<T>:
template<class T>
struct Foo {
template<typename T_ = T>
void foo(complex_value_type_t<T_> t)
requires (is_complex<T_>::value) {
}
};
The requires is not absolutely necessary then; it's already covered by complex_value_type_t<T> being defined only for complex<T>.
You just need some type to put in there, until requires can disable the function.
I would do this:
struct nullptr_value_type {using value_type = std::nullptr_t;};
using elem_or_null_t = typename std::conditional_t<is_complex<T>::value, T, nullptr_value_type>::value_type;
void foo(elem_or_null_t t)
requires (is_complex<T>::value)
{}
Use a template class as a template parameter.
#include <complex>
template<template<class> class T> struct is_complex : std::false_type {};
template<> struct is_complex<std::complex> : std::true_type {};
template<template<class> class T>
struct Foo {
void foo(typename T<double>::value_type t)//could be typename<T<TT>> if you made foo a templated function
requires (is_complex<T>::value) {
}
};
int main(){
Foo<std::complex> f;
};
But you will need what to put into it when used. I just hard-coded double but you have to add a new template parameter to Foo or make foo a templated member function
Is it possible to write a metafunction that, given a type with several occurrences of certain type template<class> class Decor, returns the type without the appearances of the class Decorator.
An example would be to convert following type
A<Decor<T<B<A<Decor<C>>>>>>
into
A<T<B<A<C>>>>
We assume that the structure of the final type is indeed a correct type, but we do not assume anything on the structure of the input type. It could be the case that some types used to construct the input type were of the form template<class...> class or any other type class.
You can use a class template and a couple of specializations like these:
template<typename T>
struct RemDec {
using type = T;
};
template<template<typename...> class C, typename... T>
struct RemDec<C<T...>> {
using type = C<typename RemDec<T>::type...>;
};
template<typename T>
struct RemDec<Decorator<T>> {
using type = typename RemDec<T>::type;
};
The class template helps to stop iterating over your chain of types.
The first specialization memorizes a class template and helps cleaning up what remains.
The last specialization removes the Decorator detected and goes on analyzing what remains.
It follows a minimal, working example:
#include<type_traits>
template<typename>
struct Decorator {};
template<typename...>
struct S {};
template<typename T>
struct RemDec {
using type = T;
};
template<template<typename...> class C, typename... T>
struct RemDec<C<T...>> {
using type = C<typename RemDec<T>::type...>;
};
template<typename T>
struct RemDec<Decorator<T>> {
using type = typename RemDec<T>::type;
};
int main() {
static_assert(std::is_same<
typename RemDec<S<Decorator<S<S<Decorator<S<int>>>>>, Decorator<S<double>>>>::type,
S<S<S<S<int>>>, S<double>>
>::value, "!");
}
As you can see by running it, any instance of Decorator is removed from the original type.
template <class T>
struct RemDec
{ using type = T; };
template <class T>
struct RemDec<Decor<T>>
{ using type = T; };
template <class T>
struct RemDec<T&>
{ using type = typename RemDec<T>::type&; };
template <class T>
struct RemDec<T&&>
{ using type = typename RemDec<T>::type&&; };
template <class T>
struct RemDec<const T>
{ using type = typename RemDec<T>::type const; };
template <class T>
struct RemDec<volatile T>
{ using type = typename RemDec<T>::type volatile; };
template <template <typename...> class TT, class... Ts>
struct RemDec<TT<Ts...>>
{ using type = TT<typename RemDec<Ts>::type...>; }
You will need even more specializations if your templates might have value- or template-template-arguments.
I want to implement a class template that:
behaves like a function
it's input and output variables are all shared.
relatively easy to use.
As a result, I construct the following:
// all input/output variable's base class
class basic_logic_parameter;
// input/output variable, has theire value and iterators to functions that reference to this variable
template <typename FuncIterator, typename ValueType>
class logic_parameter
:public basic_logic_parameter
{
private:
std::list<FuncIterator> _refedFuncs;
ValueType _val;
public:
};
// all `function`'s base class
class basic_logic_function
{
public:
virtual ~basic_logic_function() = 0;
};
// the function, has input/output variable
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base
:public basic_logic_function
{
private:
std::shared_ptr<logic_parameter<FuncIterator, R>> _ret;
std::tuple<std::shared_ptr<logic_parameter<FuncIterator, Args>>...> _args;
public:
template <std::size_t N>
decltype(auto) arg()
{
return std::get<N>(_args);
}
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N> type;
};
template <std::size_t N>
using arg_type_t = arg_type<N>::type;
decltype(auto) ret()
{
return _ret;
}
};
I wish to use as these like:
// drawing need color and a pen
struct Color
{
};
struct Pen
{
};
struct Iter
{
};
class Drawer
:public logic_function_base<Iter, void(Color, Pen)>
{
public:
void draw()
{
arg_type_t<0> pColor; // wrong
}
}
My compiler can not pass this code through, why? I just want convert a template parameter pack to std::tuple of std::shared_ptr of them.
for example:
Given struct A, int, struct C, I want to have:
std::tuple<
std::shared_ptr<logic_parameter<A>>,
std::shared_ptr<logic_parameter<int>>,
std::shared_ptr<logic_parameter<C>>,
>
The problem (once the small errors are fixed1) is that you instantiate:
logic_function_base<Iter, void(Color, Pen)>
...meaning that FuncIterator is Iter and R is void(Color, Pen), so Args is emtpy <>, so decltype(_args) is an empty std::tuple<>, and your code fails to obtain the type of the 0th element of an empty tuple, which is legit.
What you want is partial specialization of logic_function_base:
template <typename F, typename T>
class logic_function_base;
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base<FuncIterator, R(Args...)>: public basic_logic_function {
};
1 Small mistakes in your current code:
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N, decltype(_args)> type; // Missing the tuple type
};
template <std::size_t N>
using arg_type_t = typename arg_type<N>::type; // Missing a typename
This may not answer your whole question, but you could use the following trait to wrap tuple element types.
template <typename T> struct wrap;
template <typename... T>
struct wrap<std::tuple<T...>> {
using type = std::tuple<std::shared_ptr<logic_parameter<T>>...>;
}
template <typename T>
using wrap_t = typename wrap<T>::type;
You can then use it like this:
std::tuple<int,double,char> t1;
wrap_t<decltype(t)> t2;
The type of t2 is std::tuple<std::shared_ptr<logic_parameter<int>>,std::shared_ptr<logic_parameter<double>>,std::shared_ptr<logic_parameter<char>>>.
Having a class like the A, is there a way to apply it to a template like this of B, with T2 set to some type C? But without creating another template class inheriting from A.
template<typename T1, typename T2>
class A
{ };
template<template <typename T1> class T3>
class B
{ };
With C++11 using a template alias works:
template<typename T1, typename T2>
class A
{ };
template<template <typename T1> class T3>
class B
{ };
class C
{ };
template< typename T > using A1 = A< T, C >;
int main()
{
B< A1 > b;
}
without C++11, you are left with what you probably already know:
template< typename T > class A1 : A< T, C > {};
I will propose an alternative solution: do not use template template parameters.
If you write:
template <typename T> struct B {};
Then it can be used with A<int, int> or C<3> or even plain D.
Whilst it is possible to use template template parameters, it is general a bad idea. You should treat the template parameter of a class as an implementation detail and apply the golden rule: do not rely on implementation details.
If you need access to the type, somehow, then use an associated type (aka T::AssociatedType) or a trait (BTraits<T>::AssociatedType).
EDIT: dealing with multiple instantiations of the template template parameter.
Suppose we want to "erase" the template template parameter of such a class:
template <template <typename> class A>
struct Something {
template <typename T>
void doit() { A<T>::doit(); }
};
The C++ standard allocation model is to use an inner rebind structure:
template <typename T>
struct Simple {
template <typename U>
struct rebind { typedef Simple<U> type; };
};
template <typename T0, typename T1>
struct Multi {
template <typename U>
struct rebind { typedef Multi<U, T1> type; };
};
template <typename A>
struct Something {
template <typename T>
void doit() { typedef typename A::rebind<T>::type B; B::doit(); }
};
Note how you can use complex computations in rebind and nothing forces you in blindly passing the type received as parameter.
Whilst another (similar) solution is to ask for a factory (aka, the object passed itself cannot be used but it can build useful objects); for ease of use the C++ containers ask of their allocators that they be both usable in themselves and factories for other types.
Yes, you can do it using C++11's alias template:
template <typename T>
using AA = A<T, C>;
B<AA> b;
Live example
Keeping the old question. See below for resolution.
It is probably something simple, but still. I have the following C++11 code fragment:
#include <vector>
template <typename... Ts>
struct typelist
{
};
template <typename T>
struct EventContainer
{
typedef T Type;
/// TODO. Ring buffer
std::vector<T> container;
void push(const T& t)
{
EventContainer<T>::container.push_back(t);
}
virtual ~EventContainer()
{
}
};
template <template <typename...> class TL>
class EventStorage:
public EventContainer<Ts>...
{
};
class Event1
{
};
class Event2
{
};
typedef typelist<Event1,Event2> Events12;
int main()
{
EventStorage<Events12> ev;
return 0;
}
How can I make EventStorage inherit EventContainer templeted with each of the types in the typelist. I could do it with Loki:: library, but I want to use C++11 with variadic templates.
Thank you.
Resolution1: Fixing EventStorage template template issue. This will make EventStorage, multiple inherit all EventContainer templated with each type of Ts.
template <typename...>
class EventStorage
{
};
template <typename... Ts>
class EventStorage < typelist<Ts...> >:
public EventContainer<Ts>...
{
};
Now I have compile time error, on the following main():
int main()
{
EventStorage<Events12> ev;
Event1 ev1;
ev.push(ev1);
return 0;
}
In function ‘int main()’:
error: request for member ‘push’ is ambiguous
error: candidates are: void EventContainer<T>::push(const T&) [with T = Event2]
error: void EventContainer<T>::push(const T&) [with T = Event1]
Why the compiler is confused? After all I push with specific type.
GCC 4.6.1 here.
Resolution2:
As #Matthieu M. suggested I can present a forwarding method int EventStorage, but at a cost of one extra functin call:
template <typename T>
void push(const T& t)
{
EventContainer<T>::push(t);
}
According to Alexandrescu, the compiler will optimize this forward call as long as parameters are references.
Now the question is officially closed :)
Is there any reason for introducing the typelist in the first place ?
template <typename T> struct Template { void push(T) {} };
template <typename... Args>
class Storage: public Template<Args>...
{
public:
// forwarding...
template <typename T>
void push(T t) {
Template<T>& me = *this;
me.push(t);
}
};
int main() {
Storage< int, char > storage;
}
This works and you can typedef the whole Storage<...> bit.
EDIT: Following on comments regarding the possibility to "combine" types.
There are two solutions:
template <typename...> struct CombineStorage;
template <typename... A, typename... B>
struct CombineStorage<Storage<A...>, Storage<B...>> {
typedef Storage<A..., B...> type;
};
Or simply provide a typelist adapter:
template <typename... Args>
class Storage<typelist<Args...>>: public Storage<Args...> {};
At the moment, you're never even passing a typelist instantiation to the EventStorage, just the typelist template. So currently, there is no type pack to expand.
However, you should be able to unpack the typelist with a specialization and work with type packs otherwise:
template <typename...> class EventStorage;
template <typename Head, typename... Tail> class EventStorage<Head, Tail...>
: public EventContainer<Head>, EventStorage<Tail...>
{
using EventContainer<Head>::push;
using EventStorage<Tail...>::push;
};
// allows you to pass typelists for convenience
template <typename... TL> class EventStorage<typelist<TL...>>
: public EventStorage<TL...>
{
using EventStorage<TL...>::push;
};
The using declarations just pull all the push methods into the same overload set, which seems to work for me.
The alternative would be to add a template method (maybe just to the toplevel typelist specialization) which explicitly forwards to this->EventContainer<T>::push, but it would require an exact type match.