class template and member function template with requires - c++

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>

Related

When (if ever) C++ concepts must be “decayed”, do it at concept definition or at “requires”?

Imagine I have a concept that checks for some trait of a member type, e.g. its integralness. In anticipation of what is to come, let me define it in two ways:
namespace decayedAtConcept {
template <typename T>
concept hasIntegralMemberType = std::integral<typename std::decay_t<T>::MemberType>;
}
namespace notDecayedAtConcept {
template <typename T>
concept hasIntegralMemberType = std::integral<typename T::MemberType>;
}
With the following definitions
struct HasIntegralMemberType {using MemberType = int;};
struct HasNonintegralMemberType {using MemberType = double;};
struct DoesNotHaveMemberType {};
and the following function declarations
void usesIntegralMemberType1 (decayedAtConcept::hasIntegralMemberType auto&&);
void usesIntegralMemberType2 (notDecayedAtConcept::hasIntegralMemberType auto&&);
template <typename T> requires notDecayedAtConcept::hasIntegralMemberType<std::decay_t<T>>
void usesIntegralMemberType3 (T&&);
in effect, a client can try to use this library in the following way:
void client () {
HasIntegralMemberType h;
usesIntegralMemberType1(HasIntegralMemberType{});
usesIntegralMemberType1(h); // OK
//usesIntegralMemberType1(HasNonintegralMemberType{}); //note: constraints not satisfied
//usesIntegralMemberType1(DoesNotHaveMemberType{}); //note: constraints not satisfied
usesIntegralMemberType2(HasIntegralMemberType{});
//usesIntegralMemberType2(h); //error: ‘HasIntegralMemberType&’ is not a class, struct, or union type
usesIntegralMemberType3(HasIntegralMemberType{});
usesIntegralMemberType3(h); // OK again
}
The notes just demonstrate that the concept works as expected in usesIntegralMemberType1. My question is related to the error caused by the naive usage of the notDecayedAtConcept in usesIntegralMemberType2.
Apparently, the notDecayedAtConcept version of the concept is less convenient to use because any time it is used with a universal reference, it needs to be decayed in a requires clause as in usesIntegralMemberType3. We even lose the syntactic sugar we had in defining the constrained template parameter in usesIntegralMemberType1.
And now the question: are there already some guidelines which of the two strategies to use in such a situation? Or, is there any other, more transparent/convenient solution?

Concept of template class in C++20

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.

Enable member functions of class templates using concepts

So I have a concept Fooable:
template <typename T>
concept bool Fooable()
{
return requires(...){ ... };
}
And I have a class template Bar that takes type T as template parameter and I want to enable a member function only if T is Fooable:
template <typename T>
class Bar
{
public:
template // ???
requires Fooable<T>
void MemFun();
};
Is it possible in C++17 with concepts TS or in C++2a?
In both the Concepts TS and C++20 designs, functions have an optional trailing requires-clause. So you don't need to make your member function a template to constrain it:
void MemFun() requires Fooable<T>;
Constraints can go after the function in the trailing position:
template <typename T>
class Bar
{
public:
void MemFun() requires Fooable<T>;
};
Live on Godbolt

Out of line definition of template function vs in class

I wondered if there was any advantages of declaring templates function out of line vs in the class.
I'm trying to get a clear understanding of the pros and cons of the two syntax.
Here's an example:
Out of line:
template<typename T>
struct MyType {
template<typename... Args>
void test(Args...) const;
};
template<typename T>
template<typename... Args>
void MyType<T>::test(Args... args) const {
// do things
}
Vs in class:
template<typename T>
struct MyType {
template<typename... Args>
void test(Args... args) const {
// do things
}
};
Are there language features that are easier to use with the first or second version? Does the first version would get in the way when using default template arguments or enable_if? I would like to see comparisons of how those two cases are playing with different language features like sfinae, and maybe potential future features (modules?).
Taking compiler specific behavior into account can be interesting too. I think MSVC needs inline in some places with the first code snippet, but I'm not sure.
EDIT: I know there is no difference on how these features works, that this is mostly a matter of taste. I want to see how both syntaxes plays with different techniques, and the advantage of one over the other. I see mostly answers that favors one over another, but I really want to get both sides. A more objective answer would be better.
There is no difference between the two versions regarding default template arguments, SFINAE or std::enable_if as overload resolution and substitution of template arguments work the same way for both of them. I also don't see any reason why there should be a difference with modules, as they don't change the fact that the compiler needs to see the full definition of the member functions anyway.
Readability
One major advantage of the out-of-line version is readability. You can just declare and document the member functions and even move the definitions to a separate file that is included in the end. This makes it so that the reader of your class template doesn't have to skip over a potentially large number of implementation details and can just read the summary.
For your particular example you could have the definitions
template<typename T>
template<typename... Args>
void MyType<T>::test(Args... args) const {
// do things
}
in a file called MyType_impl.h and then have the file MyType.h contain just the declaration
template<typename T>
struct MyType {
template<typename... Args>
void test(Args...) const;
};
#include "MyType_impl.h"
If MyType.h contains enough documentation of the functions of MyType most of the time users of that class don't need to look into the definitions in MyType_impl.h.
Expressiveness
But it is not just increased readibility that differentiates out-of-line and in-class definitions. While every in-class definition can easily be moved to an out-of-line definition, the converse isn't true. I.e. out-of-line definitions are more expressive that in-class definitions. This happens when you have tightly coupled classes that rely on the functionality of each other so that a forward declaration doesn't suffice.
One such case is e.g. the command pattern if you want it to support chaining of commands and have it support user defined-functions and functors without them having to inherit from some base class. So such a Command is essentially an "improved" version of std::function.
This means that the Command class needs some form of type erasure which I'll omit here, but I can add it if someone really would like me to include it.
template <typename T, typename R> // T is the input type, R is the return type
class Command {
public:
template <typename U>
Command(U const&); // type erasing constructor, SFINAE omitted here
Command(Command<T, R> const&) // copy constructor that makes a deep copy of the unique_ptr
template <typename U>
Command<T, U> then(Command<R, U> next); // chaining two commands
R operator()(T const&); // function call operator to execute command
private:
class concept_t; // abstract type erasure class, omitted
template <typename U>
class model_t : public concept_t; // concrete type erasure class for type U, omitted
std::unique_ptr<concept_t> _impl;
};
So how would you implement .then? The easiest way is to have a helper class that stores the original Command and the Command to execute after that and just calls both of their call operators in sequence:
template <typename T, typename R, typename U>
class CommandThenHelper {
public:
CommandThenHelper(Command<T,R>, Command<R,U>);
U operator() (T const& val) {
return _snd(_fst(val));
}
private:
Command<T, R> _fst;
Command<R, U> _snd;
};
Note that Command cannot be an incomplete type at the point of this definition, as the compiler needs to know that Command<T,R> and Command<R, U> implement a call operator as well as their size, so a forward declaration is not sufficient here. Even if you were to store the member commands by pointer, for the definition of operator() you absolutely need the full declaration of Command.
With this helper we can implement Command<T,R>::then:
template <typename T, R>
template <typename U>
Command<T, U> Command<T,R>::then(Command<R, U> next) {
// this will implicitly invoke the type erasure constructor of Command<T, U>
return CommandNextHelper<T, R, U>(*this, next);
}
Again, note that this doesn't work if CommandNextHelper is only forward declared because the compiler needs to know the declaration of the constructor for CommandNextHelper. Since we already know that the class declaration of Command has to come before the declaration of CommandNextHelper, this means you simply cannot define the .then function in-class. The definition of it has to come after the declaration of CommandNextHelper.
I know that this is not a simple example, but I couldn't think of a simpler one because that issue mostly comes up when you absolutely have to define some operator as a class member. This applies mostly to operator() and operator[] in expession templates since these operators cannot be defined as non-members.
Conclusion
So to conclude: It is mostly a matter of taste which one you prefer, as there isn't much of a difference between the two. Only if you have circular dependencies among classes you can't use in-class defintion for all of the member functions. I personally prefer out-of-line definitions anyway, since the trick to outsource the function declarations can also help with documentation generating tools such as doxygen, which will then only create documentation for the actual class and not for additional helpers that are defined and declared in another file.
Edit
If I understand your edit to the original question correctly, you'd like to see how general SFINAE, std::enable_if and default template parameters looks like for both of the variants. The declarations look exactly the same, only for the definitions you have to drop default parameters if there are any.
Default template parameters
template <typename T = int>
class A {
template <typename U = void*>
void someFunction(U val) {
// do something
}
};
vs
template <typename T = int>
class A {
template <typename U = void*>
void someFunction(U val);
};
template <typename T>
template <typename U>
void A<T>::someFunction(U val) {
// do something
}
enable_if in default template parameter
template <typename T>
class A {
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
bool someFunction(U const& val) {
// do some stuff here
}
};
vs
template <typename T>
class A {
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
bool someFunction(U const& val);
};
template <typename T>
template <typename U, typename> // note the missing default here
bool A<T>::someFunction(U const& val) {
// do some stuff here
}
enable_if as non-type template parameter
template <typename T>
class A {
template <typename U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
bool someFunction(U const& val) {
// do some stuff here
}
};
vs
template <typename T>
class A {
template <typename U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
bool someFunction(U const& val);
};
template <typename T>
template <typename U, std::enable_if_t<std::is_convertible<U, T>::value, int>>
bool A<T>::someFunction(U const& val) {
// do some stuff here
}
Again, it is just missing the default parameter 0.
SFINAE in return type
template <typename T>
class A {
template <typename U>
decltype(foo(std::declval<U>())) someFunction(U val) {
// do something
}
template <typename U>
decltype(bar(std::declval<U>())) someFunction(U val) {
// do something else
}
};
vs
template <typename T>
class A {
template <typename U>
decltype(foo(std::declval<U>())) someFunction(U val);
template <typename U>
decltype(bar(std::declval<U>())) someFunction(U val);
};
template <typename T>
template <typename U>
decltype(foo(std::declval<U>())) A<T>::someFunction(U val) {
// do something
}
template <typename T>
template <typename U>
decltype(bar(std::declval<U>())) A<T>::someFunction(U val) {
// do something else
}
This time, since there are no default parameters, both declaration and definition actually look the same.
Are there language features that are easier to use with the first or second version?
Quite trivial a case, but it's worth to be mentioned: specializations.
As an example, you can do this with out-of-line definition:
template<typename T>
struct MyType {
template<typename... Args>
void test(Args...) const;
// Some other functions...
};
template<typename T>
template<typename... Args>
void MyType<T>::test(Args... args) const {
// do things
}
// Out-of-line definition for all the other functions...
template<>
template<typename... Args>
void MyType<int>::test(Args... args) const {
// do slightly different things in test
// and in test only for MyType<int>
}
If you want to do the same with in-class definitions only, you have to duplicate the code for all the other functions of MyType (supposing test is the only function you want to specialize, of course).
As an example:
template<>
struct MyType<int> {
template<typename... Args>
void test(Args...) const {
// Specialized function
}
// Copy-and-paste of all the other functions...
};
Of course, you can still mix in-class and out-of-line definitions to do that and you have the same amount of code of the full out-of-line version.
Anyway I assumed you are oriented towards full in-class and full out-of-line solutions, thus mixed ones are not viable.
Another thing that you can do with out-of-line class definitions and you cannot do with in-class definitions at all is function template specializations.
Of course, you can put the primary definition in-class, but all the specializations must be put out-of-line.
In this case, the answer to the above mentioned question is: there exist even features of the language that you cannot use with one of the version.
As an example, consider the following code:
struct S {
template<typename>
void f();
};
template<>
void S::f<int>() {}
int main() {
S s;
s.f<int>();
}
Suppose the designer of the class wants to provide an implementation for f only for a few specific types.
He simply can't do that with in-class definitions.
Finally, out-of-line definitions help to break circular dependencies.
This has been already mentioned in most of the other answers and it doesn't worth it to give another example.
Separating the declaration from the implementation allows you to do this:
// file bar.h
// headers required by declaration
#include "foo.h"
// template declaration
template<class T> void bar(foo);
// headers required by the definition
#include "baz.h"
// template definition
template<class T> void bar(foo) {
baz();
// ...
}
Now, what would make this useful? Well, the header baz.h may now include bar.h and depend on bar and other declarations, even though the implementation of bar depends on baz.h.
If the function template was defined inline, it would have to include baz.h before declaring bar, and if baz.h depends on bar, then you'd have a circular dependency.
Besides resolving circular dependencies, defining functions (whether template or not) out-of-line, leaves the declarations in a form that works effectively as a table of contents, which is easier for programmers to read than declarations sprinkled across a header full of definitions. This advantage diminishes when you use specialized programming tools that provide a structured overview of the header.
I tend to always merge them - but you can't do that if they are codependent. For regular code you usually put the code in a .cpp file, but for templates that whole concept doesn't really apply (and makes for repeated function prototypes). Example:
template <typename T>
struct A {
B<T>* b;
void f() { b->Check<T>(); }
};
template <typename T>
struct B {
A<T>* a;
void g() { a->f(); }
};
Of course this is a contrived example but replace the functions with something else. These two classes require each other to be defined before they can be used. If you use a forward declaration of the template class, you still cannot include the function implementation for one of them. That's a great reason to put them out of line, which 100% fixes this every time.
One alternative is to make one of these an inner class of the other. The inner class can reach out into the outer class beyond its own definition point for functions so the problem is kind of hidden, which is usable in most cases when you have these codependent classes.

Lack of orthogonality in templates between class and function

// InternalTemplate.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
template<class T>
struct LeftSide
{
static void insert(T*& newLink, T*& parent)
{
parent->getLeft() = newLink;
newLink->parent = newLink;
}
};
template<class T>
struct Link
{
T* parent_;
T* left_;
T* right_;
T*& getParent()const
{
return parent_;
}
template<class Side>
void plugIn(Link<T>*& newLink);
};
template<class T>
template<class Side>
void Link<T>::plugIn(Link<T>*& newLink)//<<-----why can't I type
//void Link<T>::plugIn<Side>(Link<T>*& newLink)<---<Side> next to plugIn
{
Side::insert(newLink,this);
}
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
I find it strange that I have to specify parameter for a class but cannot specify parameter for a function. Is there any reason why?
Function templates and class templates are complementary (I call them orthogonal, but you are free not to agree), and in template metaprogramming they actually serve orthogonal purposes.
Class templates allow you to pattern match on the template argument, ie. they provide partial specialization.
Function templates, to the contrary, don't allow partial specialization, but they allow template argument deduction, which means you don't have to write the template arguments explicitly (except for extra arguments, as in your example).
This, I think, explains the differences in syntax since they are different in what they can achieve. Moreover, function templates can have overloads, class templates cannot.
The way to combine both concepts is
1) to have helper class templates with static non template functions if you want partial specialization for function templates:
template <typename T>
struct doSomethingWithPointersHelper
{
static void act(T x) { ... }
};
template <typename T>
struct doSomethingWithPointersHelper<T*>
{
static void act(T* x) { ... }
};
// This acts as if we had a partial specialization
// for pointer types
template <typename T>
doSomethingWithPointers(T x)
{ return doSomethingWithPointersHelper<T>::act(x); }
There are other ways to achieve this in particular cases, but this approach always works.
2) To have helper template functions if you want to make use of argument deduction when constructing complex classes:
template <typename T, typename U>
struct MyComplexClass
{ ... };
template <typename T, typename U>
MyComplexClass<T, U> makeComplex(T t, U u)
{ return MyComplexClass<T, U>(t, u); }
in the standard library, you find make_pair, bind1st or mem_fun which make use of this technique.
$14/2 -
A template-declaration can appear only as a namespace scope or class scope declaration. In a function template declaration, the last component of the declarator-id shall be a template-name or operator-functionid (i.e., not a template-id). [ Note: in a class template declaration, if the class name is a simple-template-id, the declaration declares a class template partial specialization (14.5.5). —end note ]"
The standard forbids such a syntax explicitly. Refer this for more idea about template id / template name
You need to specialize on the Link struct in order to define it's template member function.
template<>
template<class Side>
void Link<int>::plugIn(Link<int>*& newLink)
{
Side::insert(newLink,this);
}
Gotta be honest, this makes my brain explode a little.