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 {};
Related
Consider the following class structure:
template <typename TType>
struct Base {public: virtual ~Base() {} };
template <typename TType>
struct Child : Base<TType> {};
template <template<typename> class Node, typename TType>
bool type(Node <TType>* node){
return dynamic_cast<Base<TType>*>(node) == nullptr;
}
int main(){
Child<int> child;
type(&child);
}
This code works fine, as long as the child has the same template type before and after casting. If this is not the case, it will of course fail. If they have different types and I provide the specific type of the inherited template, it will work, but I have a very big number of possible templates. My first instinct was to add another template:
template <template<typename TType> class Node, typename TType, typename TType2>
bool type(Node <TType>* node){
return dynamic_cast<Base<TType2>*>(node) == nullptr;
}
This will give an error "couldn't deduce template parameter", because the compiler does not know which type it is, as no corresponding parameter is passed (but I am not able to provide this in beforehand).
Is there any solution to this? I am also open to other possibilites than dynamic_cast, as my actual goal is, if the templated node is a subclass of the also templated baseclass.
I tried e.g. is_base_of without success. Something around the lines of is_base_of<Base, typeid(child)>::value did not work because of a type msimatch in the arguments.
You might use overload:
template <typename T>
constexpr std::true_type IsBaseT(const Base<T>*) { return {}; }
constexpr std::false_type IsBaseT(const void*) { return {}; }
Demo
That assumes accessible, non ambiguous base. And result is based on static type.
So you can turn that into a traits:
template <typename T>
std::true_type IsBaseTImpl(const Base<T>*); // No impl
std::false_type IsBaseTImpl(const void*); // No impl
template <typename T>
using IsBaseT = decltype(IsBaseTImpl(std::declval<T*>()));
And a more generic form:
template <template <typname> C, typename T>
std::true_type IsCTImpl(const C<T>*); // No impl
template <template <typname> C>
std::false_type IsCTImpl(const void*); // No impl
template <template <typname> C, typename T>
using IsCT = decltype(IsCTImpl<C>(std::declval<T*>()));
template <typename T>
using IsBaseT = IsCT<Base, T>;
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.
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 keep facing the situation that I have a class that takes some template parameters, that I want to be publicly available via CLASS::TYPE. For that I always do public typedefs, like this:
template <class Tx>
Class C
{
public:
typedef Tx Ty;
};
This is awkward for 2 reasons:
it feels clunky and redundant
to avoid shadowing I need to give two different names (Tx and Ty) to the same thing, which really bugs me.
Is there a better way of doing this?
You could make use of decltype syntax, deduction and tag dispatching:
template <class Tx>
struct C { };
template <class T>
struct tag { };
template <class T>
T deduceCTx(tag<C<T>>);
// now to extract type:
decltype(deduceCTx(tag<C<int>>{})) a; // a is of type int
In more general case (and when using at least c++11) you could create deduce function to extract any template type parameter using template template syntax and variadic templates:
#include <tuple>
template <class Tx>
struct C { };
template <class T>
struct tag { };
template <size_t N, template <class...> class TT, class... Args>
typename std::tuple_element<N, std::tuple<Args...>>::type
deduceAnyTypeTemplateParameter(tag<TT<Args...>>);
// now to extract type:
decltype(deduceAnyTypeTemplateParameter<0>(tag<C<int>>{})) a; // a is of type int
If you are using c++14 you could make usage of your deduction more convenient by utilizing type alias:
#include <tuple>
template <class Tx>
struct C { };
template <class T>
struct tag { };
template <size_t N, template <class...> class TT, class... Args>
typename std::tuple_element<N, std::tuple<Args...>>::type
deduceAnyTemplateParameter(tag<TT<Args...>>);
// now to use passed type:
decltype(deduceAnyTemplateParameter<0>(tag<C<int>>{})) a; // a is of type int
template <size_t N, class T>
using TemplateParameter = decltype(deduceAnyTemplateParameter<N>(tag<T>{}));
int main() {
TemplateParameter<0, C<int>> i; // i of type int
}
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 */ }
};