Specialization and template template parameters - c++

I've the following:
template <template <typename, typename> class C, class T, class A >
class TTCTest
{
public:
TTCTest(C<T, A> parameter) { /* ... some stuff... */ }
C<T, A> _collection;
};
I want to ensure that the template is only instantiated where the T and A classes are of a specific type (path and allocator respectively).
For example:
...
list<path, allocator<path> > list1;
list<int, allocator<int> > list2;
TTCTest<list> testvar(list1); // ...should work
TTCTest<list> testvar(list2); // ...should not work
...
Is this possible and what is the syntax?
Regards,
Col

You can do that with partial specialisation, where you fail to provide an implementation for the non-specialised case.
For example:
template <template <typename, typename> class C, class T, class A >
class TTCTest;
template <template <typename, typename> class C>
class TTCTest<C, path, allocator<path> >
{
// ...
};

You can create trait class to constraint instantiations. For example, limit your TTCTest construction only to path type:
template<class T, class A> class path {};
template<class T, class A> class not_path {};
template<class T> class allocation {};
template<class T>
struct Testable;
template<class T, class A>
struct Testable<path<T,A> > {};
template <template <typename, typename> class C,
class T, class A >
class TTCTest
{
public:
TTCTest(C<T, A> parameter, Testable<C<T,A> > = Testable<C<T,A> >());
C<T, A> _collection;
};
void foo()
{
path<int, allocation<int> > p;
TTCTest<path, int, allocation<int> > t(p); // compiles
not_path<int, allocation<int> > np;
TTCTest<not_path, int, allocation<int> > t1(np); // fails
}
Edit:
Since you indicated later that all you might need is partial specialization, in which case it would look like this:
template <class T, class A >
class TTCTest<path, T, A>
{
public:
TTCTest(path<T, A> parameter);
path<T, A> _collection;
};

Related

get first template parameter of a class

I have a class foo which takes two template parameters, what I want to do is defaulting the second parameter to the first template parameter of the first parameter if it exists. foo would look like
template<typename Class, typename T = typename first_template_parameter<Class>::type>
class foo
{
...
}
and if Class has been defined as template<typename A, typename B, ...> class bar I want T to be A. So for example foo<std::map<int, float>> would have Class = std::map<int, float> and T = int, foo<int, char> would have Class = int and T = char. How can I implement first_template_parameter?
Drilling down into the first template parameter requires a little bit of work involving specialization:
template<typename T> struct first_template_type;
template<template<typename T, typename ...> class t,
typename T, typename ...Args>
struct first_template_type<t<T, Args...>> {
typedef T type_t;
};
template<typename T>
using first_template_type_t=typename first_template_type<T>::type_t;
Once that's out of the way, the rest is pretty boring:
#include <map>
template<typename Class,
typename T = first_template_type_t<Class>>
class foo
{
public:
T bar;
};
foo<std::map<int, char>> Foo;
int *baz=&Foo.bar;

How to create template class with member function pointer?

Is anyone knows how to declare generalized template form for the next template specialization:
template <template <class> class Container,
class Value,
class Return,
Return (Container<Value>::*Apply)(const Value &)>
class Example<Container<Value>, Apply>
{
};
Apply must be a pointer to a member function whoes signature is unknown in template declaration.
Do you mean something like this?
template<typename T, typename F>
struct S;
template<template <typename...> class C, typename R, typename... A>
struct S<C<A...>, R(A...)> {
using Apply = R(C<A...>::*)(A...);
// ...
};
As an example:
template<typename... U>
struct T {
int f(int, char) { return 42; }
};
template<typename T, typename F>
struct S;
template<template <typename...> class C, typename R, typename... A>
struct S<C<A...>, R(A...)> {
using Apply = R(C<A...>::*)(A...);
// ...
};
int main() {
S<T<int, char>, int(int, char)>::Apply apply = &T<int, char>::f;
}
Pretty ugly, indeed, but that's what the OP (maybe) asked.

is_base_of of generic type

I'm trying to assert that template parameter would be derived from some base class. But base class is generic and in the context of assertion there is no difference between any specialization types.
How can I assert, that template parameter were derived from generic of any specialized type?
I'm trying to write it as
base_generic:
template<typename T> struct base_generic{};
derived_generic:
template<typename T> struct derived_generic : public base_generic<T>{};
class with assertion:
template<typename Tsource, typename Tderived_generic>
struct encoder {
static_assert(std::is_base_of<base_generic<typename>, Tderived_generic>::value);
};
This code compiles, but assertion fails
You may create a trait for that, something like:
namespace detail
{
template <template <typename > class C>
struct is_base_of_any_helper
{
template <typename T>
std::true_type operator ()(const C<T>*) const;
std::false_type operator() (...) const;
};
}
template <template <typename > class C , typename T>
using is_base_of_any =
decltype(detail::is_base_of_any_helper<C>{}(std::declval<const T*>()));
Demo
Note that it will fail with some edge cases such as:
multiple bases C<Tx>
private inheritance of C<T>.
From commentary of #PiotrSkotnicki
template <template <typename...> class Base, typename Derived>
struct is_base_of_template
{
using U = typename std::remove_cv<Derived>::type;
template <typename... Args>
static std::true_type test(Base<Args...>*);
static std::false_type test(void*);
using type = decltype(test(std::declval<U*>()));
};
template <template <typename...> class Base, typename Derived>
using is_base_of_template_t = typename is_base_of_template<Base, Derived>::type;
This solution works fine, example.
you can use static_assert.
See: http://en.cppreference.com/w/cpp/language/static_assert
So for example, if you have a base class
template< typename T >
class Base<T> {};
and the derived one
template< typename T >
class Derived : public Base<T> {};
with your use case
template< typename Tsource, typename Tstorage >
class Test
{
std::static_assert( std::is_base_of< base<T>, TStorage >::value );
}
It is not possible to get T without adding it as a template parameter.
But with a simple trick, you get it. You have to add a typedef to Derived:
template< typename T >
class Derived : public Base<T>
{
public:
typedef T value_type;
};
And you can use it inside of the static assertion.
template< typename Tsource, typename Tstorage >
class Test
{
std::static_assert( std::is_base_of< base<TStorage::value_type>, TStorage >::value );
}
Since Tstorage is a Derived, it has the value_type field.

Altering template template parameters in C++

I would like to design a class that creates internal types that are variants of types passed as template parameters. Something like the following, non-functional example:
template <typename T>
class BaseClass
{
public:
typedef T InternalType;
std::vector<InternalType> storage;
};
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
Base<RefinedType> refinedStorage;
};
typedef Injector<BaseClass<int> > InjectedInt; // Should store vector<pair<int, int> >
Since Base is a fully-specified type, Base<RefinedType> refinedStorage; will fail to compile. Simply using a template template parameter won't work, as the refined type needs to be based on the nested template's parameter as well as its base type.
How can I implement this pattern of creating types based on both the fully-specified and base types of a template parameter?
EDIT: I would like this to be an arbitrary-depth composite, with multiple injector types performing a cascade of transformations. Thus, passing both the template template parameter and the base parameter becomes pretty unwieldy (particularly when it comes to dealing with the base case of the composite), and an ideal solution would use the more direct syntax.
I was able to achieve this by explicitly 're-declaring' the general template inside itself:
template <typename T>
class BaseClass
{
public:
typedef T InternalType;
std::vector<InternalType> storage;
template<class T2>
using Recur = BaseClass<T2>;
};
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
typename Base::template Recur<RefinedType> refinedStorage;
};
typedef Injector<BaseClass<int> > InjectedInt; // Should store vector<pair<int, int> >
You could introduce a rebind template:
template <typename From, typename To>
struct rebind_1st;
template <template <typename... > class Cls, typename A0, typename... Args, typename To>
struct rebind_1st<Cls<A0, Args...>, To> {
using type = Cls<To, Args...>;
};
template <typename From, typename To>
using rebind_1st_t = typename rebind_1st<From, To>::type;
With which your Injector becomes:
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType,
typename Base::InternalType> RefinedType;
rebind_1st_t<Base, RefinedType> refinedStorage;
};
There is no need for a rebinding template, that over-complicates the situation. Simply have a template template type:
template<typename>
struct Injector;
template<typename T, template<typename> class Base>
struct Injector<Base<T>>{
using refined_type = std::pair<typename Base::InternalType, typename Base::InternalType>;
Base<refined_type> refined_storage;
};
You'll have to use a template specialization to get a concrete type from a template template.
This is used like so:
using injector_int = Injector<Base<int>>;
int main(){
injector_int i;
}
here's a live example
You can provide an external rebinder:
template <class Bound, class U>
struct rebinder;
template <template <class> class Binder, class B, class U>
struct rebinder<Binder<B>, U>
{
typedef Binder<U> type;
};
// Usage:
template <typename Base>
class Injector
{
public:
typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
typename rebinder<Base, RefinedType>::type refinedStorage;
};
[Live example]

Partial template template specialization

have this code:
template<typename T, template<typename, typename> class OuterCont, template<typename, typename> class InnerCont, class Alloc=std::allocator<T>>
class ContProxy {
OuterCont<T, InnerCont<T, Alloc>> _container;
};
typedef ContProxy<int, std::vector, std::list> IntCont;
But need to use T* instead of std::list<T> as InnerCont in some cases - like this:
template<typename T, template<typename, typename> class OuterCont, T*, class Alloc=std::allocator<T>>
class ContProxy {
OuterCont<T, T*> _container;
};
Is it possible to use partial specialization of 'template template' parameter for this case?
Or how to archive it with minimum headache..
It's often easier to template simply on the type. You can't really capture every situation with template templates - what if someone wants to use a container with six template parameters? So try something like this:
template <typename T, typename C>
struct ContProxy
{
typedef C container_type;
typedef typename C::second_type second_type;
container_type container_;
};
ContProxy<int, MyContainer<int, std::list<int>> p;
I would also go with kerrek's solution, but other than that, the best thing I could come up with was this.
The problem is that InnerCont is declared as template type in the base template, so you can't specialize it for raw pointer anymore. So you could create a dummy template representing a pointer and use that.
template<typename,typename> class PtrInnerCont; //just a dummy template that does nothing
template<typename T, template<typename, typename> class OuterCont, template<typename, typename> class InnerCont, class Alloc=std::allocator<T>>
class ContProxy {
OuterCont<T, PtrInnerCont<T, Alloc>> _container;
};
typedef ContProxy<int, std::vector, std::list> IntCont;
template<typename T, template<typename, typename> class OuterCont, class Alloc>
class ContProxy<T, OuterCont, PtrInnerCont, Alloc> {
OuterCont<T, T*> _container;
};
typedef ContProxy<int, std::vector, PtrInnerCont> MyCont;
You can't really do what you're doing already actually. Not in a standard way. The C++ containers don't take the same template parameters.
Do something like so:
template< typename T,
template<typename, typename> class OuterCont,
template<typename, typename> class InnerCont,
class Alloc=std::allocator<T>>
class ContProxy {
typename OuterCont<T, typename InnerCont<T, Alloc>::type>::type _container;
};
Then you can create different container generators like so:
template < typename T, typename A = std::allocator<T> >
struct vector_gen { typedef std::vector<T,A> type; };
Or your pointer one:
template < typename T, typename Ignored >
struct pointer_gen { typedef T* type; };