I'm learning templates and concepts. I'm trying to make a concept for types that are derived from a class, but this class is a template.
template<typename T>
struct CAA{};
template<typename T, typename T2>
concept DerivedFromAA = requires() {std::derived_from<CAA<T2>,T>;};
Is it possible to use such concept in a function without having to explicitly tell it the template type of the class? Is my idea wrong on how to define such concept?
template<typename T>
void conceptTestFunc(DerivedFromAA<T> auto& aa)
{
}
//...
CAA<int> aa;
conceptTestFunc<int>(aa); // Without having to tell it "int"
(I'm compiling this with Clang.)
A template is not a type.
So if CAA is a template, then CAA<int> would be a type.
A type can't be derived from a template, only from another type. This means that the check has to be done on the type, not the template.
If you on the other hand want to deduce the inner type of aa, that can be done.
#include <concepts>
template<typename T>
struct CAA{};
template<typename T>
struct CBB{};
template<typename T, typename T2>
concept DerivedFromAA = std::derived_from<CAA<T2>,T>;
template<template <typename> typename Outer, typename T>
requires DerivedFromAA<Outer<T>, T>
void conceptTestFunc(Outer<T>& aa)
{
}
int main() {
CAA<int> aa;
conceptTestFunc(aa);
CBB<int> bb;
conceptTestFunc(bb); // This fails
}
You might do
template<typename T>
concept DerivedFromAA = requires(T t) {[]<typename U>(CAA<U>&){}(t);};
static_assert(DerivedFromAA<CAA<int>>);
Demo
gcc dislikes lambda in requires, so you might create dummy helper function outside.
Related
I have two functions
template <class T> void foo(std::vector<T>* p)
and
template <class T> void foo(std::valarray<T>* p)
The code in the function bodies is identical. Is there a clever way of writing the template so I can avoid the duplication? Something like
template <class T, class Container> void foo(Container<T>* p)
I'm using C++14.
I only want to allow Container to be either std::vector or std::valarray.
You can also create type traits only for your case.
template <typename T>
struct is_vector_or_valarray : std::false_type {};
template<class T>
struct is_vector_or_valarray<std::vector<T>> : std::true_type {};
template<class T>
struct is_vector_or_valarray<std::valarray<T>> : std::true_type {};
template<typename C, typename = std::enable_if_t<is_vector_or_valarray<C>::value>>
void foo(C* p) {}
Demo
If you want to allow classes derived from std::vector and std::valarray passed in.
template<template<typename...> typename T, typename U>
struct is_tbase_of
{
private:
template<class V>
static std::pair<V, decltype(static_cast<const T<V>&>(std::declval<U>()), std::true_type{})> test(const T<V>&);
static std::pair<U, std::false_type> test(...);
public:
using _aux_type = decltype(test(std::declval<U>()));
using base_type = T<typename _aux_type::first_type>;
static constexpr bool value = _aux_type::second_type::value;
};
template<typename C,
typename = std::enable_if_t<
is_tbase_of<std::vector, C>::value
|| is_tbase_of<std::valarray, C>::value>>
void foo(C* p) {
using base_t = std::conditional_t<
is_tbase_of<std::vector, C>::value,
typename is_tbase_of<std::vector, C>::base_type,
typename is_tbase_of<std::valarray, C>::base_type>;
auto pbase = static_cast<base_t*>(p);
// operate on pbase
}
The type traits for checking if a class inherits from a template class comes from this answer. I make some subtle changes based on it(mainly for getting the base type).
As #Raymond says, c should be cast to its base pointer to operate on the sliced part. I believe it should be done in the function body, otherwise, there'll be a non-deduced context.
Demo
Note: you cannot really specialize on std::vector<> and std::valarray<>, but you can say, for the given (deduced) T, you expect std::vector<T> or std::valarray<T>. Thus aliases will also be resolved.
The trick is, you templetize for a template class C and a type T (and possibly further parameters, as in std), then use std::enable_if<> that only resolves (to void in this case) when either std::vector<T> or std::valarray<T> was resolved.
Also note, you might want to allow custom allocators et. al., i.e., instead of a single T, it's recommended to use typename... Ts for the container.
#include <iostream>
#include <vector>
#include <valarray>
#include <type_traits>
template<template<class...> class C, typename T>
auto foo(C<T>* arg) -> std::enable_if_t<std::is_same<C<T>, std::vector<T>>::value || std::is_same<C<T>, std::valarray<T>>::value>
{
}
int main() {
std::vector<int> v;
std::valarray<int> va;
//std::pair<int, int> p; // this should fail
foo(&v);
foo(&va);
//foo(&p); // this fails as expected
return 0;
}
If you also want to handle derived classes, you might use std::is_base_of<> - but as for classes in std namespace, it's not recommended to derive from them.
With concepts, C++20 provides nice syntax like
template<typename T>
concept SomeConcept = true; // stuff here
template<typename T>
requires SomeConcept<T>
class Foo;
template<SomeConcept T>
class Foo;
where the two ways of concept restricting the class are equivalent, but the latter is just more concise.
If i now have some template template concept like
template<template<typename> typename T>
concept SomeOtherConcept = true; // stuff here
template<template<typename> typename T>
requires SomeOtherConcept<T>
class Foo;
i do not know the non-verbose (concise / short) syntax for this without an requirement clause, as things like
template<template<typename> SomeotherConcept T>
class Foo;
template<template<SomeOtherConcept> typename T>
class Foo;
did not work, so
What is the correct syntax for declaring such a template template class with a concept restriction to the template template parameter?
What is the correct syntax for declaring such a template template class with a concept restriction to the template template parameter?
The only way to write a constraint that depends on a template template parameter or a non-type template parameter is with a requires-clause. The shorter type-constraint syntax is only available for concepts that constrain types (hence the name type-constraint):
template <typename T> concept Type = true;
template <template <typename...> class Z> concept Template = true;
template <auto V> concept Value = true;
// requires-clause always works
template <typename T> requires Type<T> struct A { };
template <template <typename...> class Z> requires Template<Z> struct B { };
template <auto V> requires Value<V> struct C { };
// type-constraint only for type concepts
template <Type T> struct D { };
// abbreviated function template definitely only for type concepts
void e(Type auto x);
This is a trick that I have used before.
Define a lambda in the primary expression using a noop-like function as shown:
void noop(auto) {}
//...
template<typename T>
concept SomeConcept = true;
/*
template <template<typename>SomeConcept T>
struct Example {};
*/ //does not work
template <template<typename>typename T>
requires requires() {
{
noop(
[]<typename TArg> requires SomeConcept<typename T<TArg>> (){}
)
};
}
struct Example {};
Say I have a simple template like this:
template<typename T>
class A {};
And I want to specify that the type-parameter T is of some unrelated type X<U> where U is not known (or unspecifyable).
Is there a way how to express that as a concept?
Is there a way how to express that as a concept?
You don't need a concept, class template specialization works just fine in your case.
As an example, you can do this:
template<typename T>
class A;
template<typename U>
class A<X<U>> { /* ... */ };
This way, unless A is instantiated with a type of the form X<U> (where U is unknown), you'll get a compile-time error because the primary template isn't defined. In other terms, it won't work for all the types but X<U> (for each U), where the latter matches the class template specialization that has a proper definition.
Note that I assumed X is a known type. That's not clear from your question.
Anyway, if it's not and you want to accept types of the form X<U> for each X and each U, you can still do this:
template<typename T>
class A;
template<template<typename> class X, typename U>
class A<X<U>> { /* ... */ };
As a minimal, working example:
template<typename>
struct S {};
template<typename>
class A;
template<typename U>
class A<S<U>> {};
int main() {
A<S<int>> aSInt;
A<S<double>> aSDouble;
// A<char> aChar;
}
Both A<S<int>> and A<S<double>> are fine and the example compiles. If you toggle the comment, it won't compile anymore for A<char> isn't defined at all.
As a side note, if you don't want to use class template specialization and you want to simulate concepts (remember that they are not part of the standard yet and they won't be at least until 2020), you can do something like this:
#include<type_traits>
template<typename>
struct X {};
template<typename>
struct is_xu: std::false_type {};
template<typename U>
struct is_xu<X<U>>: std::true_type {};
template<typename T>
struct A {
static_assert(is_xu<T>::value, "!");
// ...
};
int main() {
A<X<int>> aXInt;
A<X<double>> aXDouble;
// A<char> aChar;
}
That is, given a generic type T, static assert its actual type by means of another structure (is_xu in the example) that verifies if T is of the form X<U> (for each U) or not.
My two cents: the class template specialization is easier to read and understand at a glance.
template <typename T, template <typename> class C>
concept bool Template = requires (T t) { {t} -> C<auto>; };
Now given a class template:
template <typename T>
struct X {};
a type template parameter can be constrained using:
template <typename T> requires Template<T, X>
class A {};
or:
template <Template<X> T>
class A {};
DEMO
This will work also for types derived from X<U>.
I would like to specialize default_delete<_Ty> for all objects derived off of MyBaseClass. This was my best attempt:
template <typename T>
struct default_delete<typename enable_if<is_base_of<MyBaseClass, T>::value, T>::true_type>
{
...
};
The compiler seems to be unable to recognize that my type parameter 'T' is being used, which is understandable given that it is 'downstream' from a 'typename' keyword. Is what I'm trying to accomplish possible?
As 0x499602D2 states in comment, it is not possible without an extra dedicated template parameter. you may use your own deleter as follow:
template <typename T, typename Enable = void>
struct my_default_delete : public std::default_delete<T> {}; // default to std::default_delete<T>
template <typename T>
struct my_default_delete<T, typename std::enable_if<std::is_base_of<MyBaseClass, T>::value>::type>
{
void operator() (T* ) { /* Your specific implementation */ }
};
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