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.
Related
Is there a way to test std::is_base_of<A, B> when A is a template class?
template <typename X, typename Y> class A {};
template <typename X> class B : public A<X, char> {};
I want to statically test something like, std::is_base_of<A, B<int>> meaning, B is derived from any specialization of A.
(To make it more general, let's say we don't know the way B specializes A, i.e. B<X> derives from A<X, char>)
One way to solve would be to derived A from a (non-template) class say C, and then check std::is_base_of<C, B<int>>. But is there another way to do this?
You may do the following:
template <template <typename...> class C, typename...Ts>
std::true_type is_base_of_template_impl(const C<Ts...>*);
template <template <typename...> class C>
std::false_type is_base_of_template_impl(...);
template <typename T, template <typename...> class C>
using is_base_of_template = decltype(is_base_of_template_impl<C>(std::declval<T*>()));
Live Demo
but will fail with multiple inheritance or private inheritance from A.
With Visual Studio 2017 this will fail when the base class template has more than one template parameter, and it is unable to deduce Ts...
Demo
VS Bug Report
Refactoring solves the problem for VS.
template < template <typename...> class base,typename derived>
struct is_base_of_template_impl
{
template<typename... Ts>
static constexpr std::true_type test(const base<Ts...> *);
static constexpr std::false_type test(...);
using type = decltype(test(std::declval<derived*>()));
};
template < template <typename...> class base,typename derived>
using is_base_of_template = typename is_base_of_template_impl<base,derived>::type;
Live Demo
Bit late to the party here but I wanted to give a variant of the above
template < template <typename...> class Base,typename Derived>
struct is_base_of_template
{
// A function which can only be called by something convertible to a Base<Ts...>*
// We return a std::variant here as a way of "returning" a parameter pack
template<typename... Ts> static constexpr std::variant<Ts...> is_callable( Base<Ts...>* );
// Detector, will return type of calling is_callable, or it won't compile if that can't be done
template <typename T> using is_callable_t = decltype( is_callable( std::declval<T*>() ) );
// Is it possible to call is_callable which the Derived type
static inline constexpr bool value = std::experimental::is_detected_v<is_callable_t,Derived>;
// If it is possible to call is_callable with the Derived type what would it return, if not type is a void
using type = std::experimental::detected_or_t<void,is_callable_t,Derived>;
};
template < template <typename...> class Base,typename Derived>
using is_base_of_template_t = typename is_base_of_template<Base,Derived>::type;
template < template <typename...> class Base,typename Derived>
inline constexpr bool is_base_of_template_v = is_base_of_template<Base,Derived>::value;
This uses the proposed is_detected machanism which I think makes the intent of the test a bit clearer. However I can now get the type(s) with which the base class is instantiated at the same time which I find useful. So I can write
template <typename T, typename U> struct Foo { };
struct Bar : Foo<int,std::string> { };
static_assert( is_base_of_template_v<Foo,Bar> );
// The variant type contains the types with which the Foo base is instantiated
static_assert( std::is_same_v<std::variant<int,std::string>,is_base_of_template_t<Foo,Bar>> );
The following solution works with protected inheritance.
template <template <typename...> class BaseTemplate, typename Derived, typename TCheck = void>
struct test_base_template;
template <template <typename...> class BaseTemplate, typename Derived>
using is_base_template_of = typename test_base_template<BaseTemplate, Derived>::is_base;
//Derive - is a class. Let inherit from Derive, so it can cast to its protected parents
template <template <typename...> class BaseTemplate, typename Derived>
struct test_base_template<BaseTemplate, Derived, std::enable_if_t<std::is_class_v<Derived>>> : Derived
{
template<typename...T>
static constexpr std::true_type test(BaseTemplate<T...> *);
static constexpr std::false_type test(...);
using is_base = decltype(test((test_base_template *) nullptr));
};
//Derive - is not a class, so it is always false_type
template <template <typename...> class BaseTemplate, typename Derived>
struct test_base_template<BaseTemplate, Derived, std::enable_if_t<!std::is_class_v<Derived>>>
{
using is_base = std::false_type;
};
Surprisingly, on VS2017, it works with multiple inheritance from the same template, like C<
int > and C< float > both. (have no idea how!)
Check the
Link to test code
Based on Evgeny Mamontov answer I believe the proper solution is
template <template <typename...> class BaseTemplate, typename Derived>
struct test_base_template<BaseTemplate, Derived, std::enable_if_t<std::is_class_v<Derived>>> : Derived
{
template<typename...T>
static constexpr std::true_type test(BaseTemplate<T...> *);
static constexpr std::false_type test(...);
using is_base = decltype(test((Derived *) nullptr));
};
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]
The question inspired by recently arised question about extended std::is_base_of type trait.
Is there any technique, which allows us to distinguish between ordinary template parameter and template template parameter in modern C++ or its extensions (say, -std=gnu++1z clang++/g++)?
namespace details
{
template< /* ??? */ base >
struct is_derived_from;
template< typaneme base >
struct is_derived_from< base >
{
static std::true_type test(base *);
static std::false_type test(void *);
};
template< template< typename ...formal > base >
struct is_derived_from< /* ??? */ >
{
template< typename ...actual > // actual parameters must be here!
static std::true_type test(base< actual... > *);
static std::false_type test(void *);
};
} // namespace details
template< typename derived, /* ??? */ base >
using is_derived_from = decltype(details::is_derived_from< /* ? base< ? > */ >::test(std::declval< typename std::remove_cv< derived >::type * >()));
In positive case it allows us to make some of useful type traits much more powerfull (for example, STL's std::is_base_of).
I think it requires a language feature as a "generalized typenames", isn't it?
There can be only one set of template parameters for class templates, but you can use overloading constexpr function templates instead that dispatches to the appropriate class template. Take the is_derived_from trait in the linked question, with an extra SFINAE parameter so that you don't get a hard error when B is an inaccessible or ambiguous base:
#include <type_traits>
namespace detail
{
template <template <class...> class B, typename Derived>
struct is_derived_from
{
using U = typename std::remove_cv<Derived>::type;
template <typename... Args,
typename = std::enable_if_t<
std::is_convertible<U*, Base<Args...>*>::value>>
static auto test(B<Args...>*)
-> typename std::integral_constant<bool
, !std::is_same<U, B<Args...>>::value>;
static std::false_type test(void*);
using type = decltype(test(std::declval<U*>()));
};
using std::is_base_of; // may want to use is_convertible instead to match
// the semantics of is_derived_from
}
template <template <class...> class B, typename Derived>
constexpr bool my_is_base_of() { return detail::is_derived_from<B, Derived>::type::value; }
template <class B, typename Derived>
constexpr bool my_is_base_of() { return detail::is_base_of<B,Derived>::value; }
struct B {};
struct D : B {};
template<class ...>
struct B2 {};
struct D2 : B2<int, double> { };
int main() {
static_assert(my_is_base_of<B2, D2>(), "Oops");
static_assert(my_is_base_of<B, D>(), "Oops");
static_assert(my_is_base_of<B2<int, double>, D2>(), "Oops");
static_assert(!my_is_base_of<B, D2>(), "Oops");
}
Demo.
You asked:
Is there any technique, which allows us to distinct between ordinary template parameter and template template parameter in modern C++ or its extensions (say, -std=gnu++1z clang++/g++)?
Seems to me like you need something like:
template <typename T>
struct is_template_template : public std::false_type
{
};
template <typename T1, template <typename T> class T2>
struct is_template_template<T2<T1>> : std::true_type
{
};
Example Program
#include <iostream>
template <typename T>
struct is_template_template : public std::false_type
{
};
template <typename T1, template <typename T> class T2>
struct is_template_template<T2<T1>> : std::true_type
{
};
template <typename T> struct A {};
struct B {};
int main()
{
std::cout << std::boolalpha;
std::cout << is_template_template<A<int>>::value << std::endl;
std::cout << is_template_template<B>::value << std::endl;
return 0;
}
Output:
true
false
There is std::is_base_of in modern STL. It allow us to determine whether the second parameter is derived from first parameter or if they are the same classes both or, otherwise, to determine is there no such relation between them.
Is it possible to determine whether the one class is derived from some concrete template class without distinction of which concrete actual parameters involved to its specialization?
Say, we have;
template< typename ...types >
struct B {};
And
template< typename ...types >
struct D : B< types... > {};
Is it possible to define a type trait:
template< typename T > is_derived_from_B;
Such that it is derived from std::true_type when T is any specialization of D and derived from std::false_type if T is not derived from any specialization of B?
If you can assume that a derived type uses a public inheritance from B<Args...> (and so the upcasting is possible), then you can use the following SFINAE:
namespace detail
{
template <typename Derived>
struct is_derived_from_B
{
using U = typename std::remove_cv<
typename std::remove_reference<Derived>::type
>::type;
template <typename... Args>
static auto test(B<Args...>*)
-> typename std::integral_constant<bool
, !std::is_same<U, B<Args...>>::value>;
static std::false_type test(void*);
using type = decltype(test(std::declval<U*>()));
};
}
template <typename Derived>
using is_derived_from_B = typename detail::is_derived_from_B<Derived>::type;
Tests:
static_assert(is_derived_from_B<const D<int, char, float>>::value, "!");
static_assert(!is_derived_from_B<int>::value, "!");
static_assert(!is_derived_from_B<B<int,int>>::value, "!");
static_assert(!is_derived_from_B<std::vector<int>>::value, "!");
DEMO 1
It can be generalized to accept any base class template:
namespace detail
{
template <template <typename...> class Base, typename Derived>
struct is_derived_from_template
{
using U = typename std::remove_cv<
typename std::remove_reference<Derived>::type
>::type;
template <typename... Args>
static auto test(Base<Args...>*)
-> typename std::integral_constant<bool
, !std::is_same<U, Base<Args...>>::value>;
static std::false_type test(void*);
using type = decltype(test(std::declval<U*>()));
};
}
template <template <typename...> class Base, typename Derived>
using is_derived_from_template
= typename detail::is_derived_from_template<Base, Derived>::type;
Tests:
static_assert(is_derived_from_template<B, const D<int, int>>::value, "!");
static_assert(!is_derived_from_template<B, int>::value, "!");
static_assert(!is_derived_from_template<B, B<int, int>>::value, "!");
static_assert(!is_derived_from_template<B, std::vector<int>>::value, "!");
DEMO 2
I want to propose another solution, that will also work in case of private inheritance. Downsides are that it requires you to modify the base class template and it is base class-specific.
Assuming your base class is template< typename... Args > class Base, you need to add a friend function to it:
template< /*whatever*/ > class Base {
//...
template< typename T >
friend std::enable_if_t<
std::is_base_of<Base, T>::value
> is_derived_from_Base_impl(T const&); //unevaluated-only
};
Then, you can write your trait:
template< typename T, typename Enable=void >
struct is_derived_from_Base : std::false_type { };
template< typename T >
struct is_derived_from_Base<T,
decltype(is_derived_from_Base_impl(std::declval<T const&>()))
> : std::true_type { };
This trait won't work in Visual Studio 2015 prior to Update 1, you'll have to write something like:
namespace is_derived_from_Base_adl_barrier {
struct no{}; //anything but void
no is_derived_from_Base_impl(...);
template< typename T >
struct is_derived_from_Base : std::is_void<decltype(
is_derived_from_Base_impl(std::declval<T const&>());
)> { };
}
using is_derived_from_Base_adl_barrier::is_derived_from_Base;
The thing works because argument-name dependent lookup will find the friend function despite the private inheritance, and the friend function (or functions, if multiple are found) will then check is_base_of on an actual specialization.
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;
};