I'm new in advanced usage of templates and concepts, so here is a liitle bit complex problem:
I have some Traits concept of many traits for each of Source classes:
template<typename _Traits>
concept Traits = requires
{
std::same_as<std::decay_t<decltype(_Traits::token)>, std::string_view>;
};
I have some template class that uses this concept to handle object_one with various traits (for example, half of Source classes returns object_one):
template <concepts::Traits _Traits>
class Object_one_handler final
{
static std::string handle_object(const object_one& obj) {/*...*/}
};
Then I have Objects_handlers concept of handlers for various objects from set {object_one, object_two, object_three} from various Sources with their Traits:
template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object>
concept Objects_handlers = requires(const _Object& obj)
{
// has handle_object method
{ _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>;
};
Finally, I creating some database with specified as template parameter Object_handler:
template<concepts::Objects_handlers _handler>
class database
{...};
(Actually all of concepts have additional requirements, but it doesn't matter here)
So problem is in last Objects_handlers concept:
template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object>
concept Objects_handlers = requires(const _Object& obj)
{
// has handle_object method
{ _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>;
^^^^^^^
};
I can't check _Objects_handlers method without template parameter (obviously) and I can't properly set the template parameter which must be one of Traits.
How can I do that?
And actually it may be problem in usage of Objects_handlers in template of database class, so one more question: how to use it?
P.S. It can be XY problem or not about concepts at all... Maybe composition with strategy pattern will be more usefull, but still want try to create this maybe useless, but workable concept.
Let's reduce this problem a lot.
template <typename T>
struct C {
void f();
};
Now, your goal is to write a concept that takes any class template (e.g. C) and checks that every specialization of it has a nullary member function named f.
template <template <typename> class Z>
concept HasF = requires (Z<???> z) {
z.f();
};
The problem is - class templates in C++ just don't work like this. Even for a particular class template, like C, you can't require that every specialization has f. There's no way to ensure that like somebody, somewhere, didn't add:
template <> struct C<std::vector<std::list<std::deque<int>>>> { };
All you can do is check that a specific type has a nullary member function named f. And that's:
template <typename T>
concept HasF = requires (T t) { t.f(); };
The type-constraint syntax, template <Concept T>, is only available for concepts that constrain types, not concepts that constrain templates or values.
Related
I have a template class called Speaker, with a template member function called speak. These both have a requires clause. How do I define the member function outside of the class in the same header file?
// speaker.h
#include <concepts>
namespace prj
{
template <typename T>
requires std::is_integral<T>
struct Speaker
{
template <typename U>
requires std::is_integral<U>
const void speak(const Speaker<U> &speaker);
};
// what do I put here?
const void Speaker<T>::speak(const Speaker<U> &speaker)
{
// code
}
}
The rules for defining template members of class templates are the same in principle as they were since the early days of C++.
You need the same template-head(s) grammar component(s), in the same order
template <typename T> requires std::is_integral_v<T>
template <typename U> requires std::is_integral_v<U>
const void Speaker<T>::speak(const Speaker<U> &speaker)
{
// code
}
The associated constraint expression and template <...> form the template-head together.
As an aside:
const qualified return types are redundant in the best case, or a pessimization in the worst case. I wouldn't recommend it (especially over void).
I'd also recommend using concepts (std::integral) if including the library header, not type traits (std::is_integral) that may or may not be included. The concepts allow for the abbreviated syntax, which is much more readable:
template<std::integral T>
template<std::integral U>
What's the idiomatic way for constraining a type template parameter so that it only accepts instantiations of a specific template?
e.g.,
template<typename P>
class C {
C() = default;
...
};
template<typename T>
class Accepted {
...
};
template<typename T>
class Other {
...
};
C<Accepted<float>> obj1; // should compile
C<Accepted<int>> obj2; // should compile
C<Other<int>> obj3; // should not compile
C<double> obj4; // should not compile
Specialization is the answer.
template<typename P> class C;
template<typename T>
class Accepted {
...
};
template<typename P>
class C<Accepted<P>> {
C() = default;
...
};
The above makes any C<Accepted<T>> be well-formed because it chooses the specialization when instantiating. While any sort of other C<T> chooses the primary specialization, which is not defined, and so will not compile.
I see two possible answers without knowing more about the context.
template<typename T> class C;
template<template<typename> typename TT, typename T> class C<TT<T>> {
... static_assert(std::is_same<TT<T>, Accepted<T>>::value, "The given type is not an instantiation of Accepted!"); ...
}
This is only so helpful - what is so special about Accepted? You may have a second template, e.g. SortedAccepted<T>, that meets the same requirements, but you've set out to constrain the template argument to Accepted<T>.
One option is to design Accepted as a contract so that derivations from it must satisfy the same constraints as Accepted itself:
template<template<typename> typename TT, typename T> class C {
... static_assert(std::is_base_of<Accepted<T>, TT<T>>::value,
"The given type is not a derivation of Accepted!"); ...
};
This follows from the design principle that Accepted should be extended, but not modified, by its derivations. From the previous example, maybe Accepted is required to have an idempotent 'sort' method -- accepted.sort().sort() == accepted.sort() -- whereas SortedAccepted implicitly retains this property, but additionally provides sorted_accepted.sort() == sorted_accepted. You have nothing to lose in allowing a SortedAccepted wherever you expect an Accepted, but plenty to gain!
If I understood your problem correctly, you might be interested in Traits and Concepts.
Type traits as seen in <type_traits> and Boost's extensions are reified contracts, providing compile-time guarantees about collections sharing traits, expressions of these, and so on. For example, S s; T t; auto u = s + t where std::is_arithmetic<S>::value and std::is_arithmetic<T>::value are true, guarantees that std::is_arithmetic<decltype(u)>::value is true; if either is_floating_point, so is u.
Concepts are the next logical step from type traits: essentially, the reified requirement of traits. (See: 'Concepts Lite')
I want to implement two simple abstract classes like so:
class Hashable {
public:
virtual Int hashValue() = 0;
};
template <typename T>
class Equatable {
virtual Bool operator == (const T& other) = 0;
}
These classes will give me the opportunity of partial template specialization in my new dictionary class.
However, I could not make them to work. Here is the declaration of my dictionary class:
template <Hashable Key, typename Value>
class Dictionary {
.
.
.
};
The problem is, key should also be Equatable because hashability should require it.
So, I have two questions:
Can we rewrite Equatable<T> class to have no template arguments? Does C++ have any keyword referring to current type of the class?
In my opinion, Hashable had better inherit from Equatable class. How to achieve this without new template definition on Hashable (if my first question is answered yes, this is already solved then)?
What would be the best object-oriented approach here? To have an interface class with template arguments seems tacky.
Thank you.
What you're basically looking for is Concepts, with which you'd write something like:
template <class T>
concept bool Hashable()
{
return requires(T t, T u) {
{t.hashValue()} -> size_t;
{t == u} -> bool;
};
}
template <Hashable Key, class Value>
class Dictionary {
...
};
But that won't even be in C++17.
Until then, we can write this sort of thing in C++14 using void_t:
template <class...> using void_t = void;
template <class T, class = void>
struct Hashable : std::false_type { };
template <class T>
struct Hashable<T, void_t<
std::enable_if_t<std::is_same<std::declval<T&>().hashValue(), std::size_t>::value>,
decltype(std::declval<T&>() == std::declval<T&>())
>>
: std::true_type { };
template <class Key, class Value>
class Dictionary {
static_assert(Hashable<Key>::value, "Key must be Hashable<>");
...
};
Note that in both cases, we're requiring the Key type to have this functionality - we're not requiring the Key to inherit it virtually. This is far more efficient. No virtual dispatch necessary.
What would be the best object-oriented approach here?
To not use an object-oriented approach.
I believe that
template <Hashable Key, typename Value>
does not actually do what you expect it to do. Consider:
template <int Key, typename Value> class x{};
now, you can instantiate x<1, int> and x<2, int>, but these are not merely different objects, but different types. So, in your case, your Hashable object would become part of the type (so it would have to be generated during compilation, not at runtime).
What you most probably want instead is - like Wojciech Frohmberg mentioned in the other answer:
template <typename K, typename V>
class Dict {
...
static_assert(std::is_base_of<K, Hashable>::value, "Only Hashable can be the key);
}
or enable_if or some other template magic included from type_traits.
What you're looking for are concepts, that didn't even make C++17, or typeclasses (available in other languages, like Haskell or Scala)
If you really want to use object-oriented approach here, go for something like:
template <typename Value>
class Dict {
Dict(std::shared_ptr<Hashable>, Value)
{}
}
However, it's not a typical implementation, so I wouldn't recommend it
In C++ there are 2 template types (to my knowledge): template classes and template functions. Why is it not possible to have a template of template? (be it class, or function, or other template). Has it ever been considered in standards? Does it break C++ syntax/spirit in a way?
I know it may sound crazy, and it's easy to get around.
What is possible with C++:
template<bool b>
class TemplateDependingOnBool
{
public:
template<typename T>
class TheTemplateWeWant{};
}
What would be great:
template<bool b>
template<typename T>
class TheTemplateWeWant{};
and call it in a policy-based style (that's where it's really interesting):
template<typename T, template<typename> class ThePolicy = TheTemplateWeWant<true> >
class Foo {};
The way it's possible to do now is to use:
template<typename T,
template<typename> class ThePolicy = TemplateDependingOnBool<true>::TheTemplateWeWant >
class Foo{};
which is not very elegant.
EDIT:
I know I can template on 2 parameters. The goal is to use the underlying template class (the templated template) as something by itself, be it in a template alias or a template template parameter (as shown in my example).
Policy-based design is a reference to Andrei Alexandrescu's Modern C++ Design, which is the main reason why the feature I'm asking might be useful (because templates are used as template parameters).
With C++11, you're wrong in assuming only two types of templates. There are also type aliases which allow
template <bool b, typename T>
class TheTemplateWeWant { ... };
template<typename T>
using ThePolicy = TheTemplateWeWant<true, T>
If I'm understanding what you're asking correctly (and I'm not entirely clear on your question), then you could write your template taking two parameters:
template <bool b, typename T>
class TheTemplateWeWant { ... };
add a metafunction to partially apply the bool:
template <bool b>
struct PartiallyWant {
template <typename T>
using type = TheTemplateWeWant<b, T>;
};
and then pass that as your policy:
template<typename T,
template<typename> class ThePolicy = PartiallyWant<true>::type >
class Foo { ... };
Foo<char, PartiallyWant<false>::type> foo;
So why not just layer the templates like you propose? The simple answer is that there's no reason to. If TheTemplateWeWant has two template parameters (bool b and typename T, regardless of whether it's an "inner" class or not), then we should express it as such. And if we want to only apply one type or the other, that's something that has fewer use-cases than a general template while also being solvable with just a few lines of boilerplate. Additionally, what if we had such a feature, and now I want to partially apply the T instead of the b? With a few lines of boilerplate I can again accomplish the same thing, but with the layering this would be impossible.
As far as i know you cand you simply that, and it works just as you want - class templated with 2 parameters.
template<bool b, typename T>
class TheTemplateWeWant{}; //valid in C++
What you're describing is partial binding of template parameters, just like std::bind can turn a binary function into a unary function.
For metaprogramming madness, there's Boost.MPL. They do have a template boost::mpl::bind.
I'm trying to specify a concept to constrain a higher kinded type that has a member function template using Concepts Lite. However I am not able to find inside the technical specification or the tutorial a clause dealing with templated statements inside a concept.
How is this done?
Example: suppose I have the higher kinded type HKT with a member function template F:
template<class T>
struct HKT {
template<class U> // this looks like e.g. rebind in std::allocators
auto F(U) -> HKT<U>;
};
and that now I want to specify a concept for constraining these higher kinded types:
template <template <class> class HKT, class T>
concept HKTWithTemplateMemberFunctionF {
return requires(HKT<T> h) { // HKT<T> is a type, h is an object
// HKT<T> needs to have a member function template that
// returns HTK<U> where the type U is to be deduced and
// it can be any type (it is unconstrained)
template<class U> // is there a syntax for this?
h.F(std::declval<U>()) -> HKT<U>;
}
}
Note that I could do something like:
template <template <class> class HKT, class T, class U>
concept HKTWithTemplateMemberFunctionF {
return requires(HKT<T> h) {
h.F(std::declval<U>()) -> HKT<U>;
}
}
but this means that I need to know U at constraint site.
I don't really care if substitution for a given U fails or not although I can see why this could be a problem: e.g. apply a constraint to be sure your function doesn't fail and then fails cause the constraint was satisfied but at instantiation time substitution failed in the member function template (would it help if the member function template was constrained?).
Long story short, right now you (I?) have to provide a specific U:
template <template <class> class HKT, class T, class U = T>
concept HKTWithTemplateMemberFunctionF {
return requires(HKT<T> h) { // HKT<T> is a type, h is an object
h.F(std::declval<U>()) -> HKT<U>;
}
}
since the compiler cannot prove for all types U that might ever exist that the member-function template will work, that is, the following is hopeless:
template <template <class> class HKT, class T>
concept HKTWithTemplateMemberFunctionF {
return requires(HKT<T> h) {
template<class U> // for all those Us that haven't been written yet...
h.F(std::declval<U>()) -> HKT<U>;
}
}
In an hypothetical designed-in-5-min concepts-lite implementation where we are able to constrain U just a little-bit:
template <template <class> class HKT, class T,
InputIterator U = InputIterator() /* imaginary syntax */ >
concept HKTWithTemplateMemberFunctionF {
return requires(HKT<T> h) {
h.F(std::declval<U>()) -> HKT<U>; // Is InputIterator enough to instantiate F?
}
}
the compiler would only need to check if a model of InputIterator is enough to instantiate h.F, which is possible even if h.F is not constrained! Additionally providing U just checks that it models InputIterator, no need to even try to check h.F for U since InputIterator is enough. This could be used to optimize compile-time performance and...
...would probably interact in surprising ways with SFINAE, since AFAIK you can have a concept-overloaded function (e.g. for InputIterator) that accepts all input iterators except that one (SFINAE! why would anyone do that?!), and thus could pass concept-checking but blow at instantiation time... sad.
Let's think about the requirements you want from your comment:
// HKT<T> needs to have a member function template that
// returns HTK<U> where the type U is to be deduced and
// it can be any type (it is unconstrained)
While Concepts requires us to base our constraints around concrete types, we can be smart in our selection of which concrete types we use. What do you mean by U is any type. Really any type at all, whatsoever? Think about the smallest possible set of constraints you have on U and let's build a type that satisfies them. This is known as an archetype of U.
My goto first thought for "any type" would actually be a semiregular type. A type that is default constructible, copyable, and assignable. All the normal goodies:
namespace archetypes {
// private, only used for concept definitions, never in real code
struct Semiregular { };
}
archetypes::Semiregular is a concrete type, so we can use it to build a concept:
template <template <class> class HKT, class T>
concept bool HKTWithTemplateMemberFunctionF =
requires(HKT<T> h, archetypes::Semiregular r) {
{h.F(r)} -> HKT<archetypes::Semiregular>
};
archetypes::Semiregular is a private type. It should not be known to HKT, and so if h.F(r) is well-formed and returns a type convertible to HKT<archetypes::Semiregular>, it's almost certainly a member function template.
The question then is, is this a good archetype? Do we need U to be semiregular, or would irregular types work too? The fewer operations that you need, the fewer should be present in your archetype. Maybe all you need is that U is movable:
namespace archetypes {
// private, only used for concept definitions, never in real code
struct Semiregular { };
struct Moveable {
Moveable() = delete;
Moveable(Moveable&& ) noexcept(false);
Moveable(Moveable const& ) = delete;
~Moveable() = default;
Moveable& operator=(Moveable const& ) = delete;
Moveable& operator=(Moveable&& ) noexcept(false);
};
}
template <template <class> class HKT, class T>
concept bool HKTWithTemplateMemberFunctionF =
requires(HKT<T> h, archetypes::Moveable m) {
{ h.F(m) } -> HKT<archetypes::Moveable>
};
We're testing the same idea - invoking F() with a type that isn't well-known and excepting the return type to reflect that, hence requiring it to be a function template. But now we're giving less functionality to the type. If F() works on any, it'll work on archetypes::Moveable.
Keep iterating on this idea until you've really pared down the required functionality to the bare minimum. Maybe you don't even need the archetype to be destructible? Writing archetypes is hard, but in cases like this, it's important to get right.