What is the difference between std::invocable and std::regular_invocable concepts? - c++

What is the difference between std::invocable and std::regular_invocable? Based on the description from
https://en.cppreference.com/w/cpp/concepts/invocable I would expect that the std::regular_invocable concept doesn't allow to change the state of of the function object when it is called (or at least the result of the calling should always return the same result).
Why the code below compiles?
Compiled with a command: g++-10 -std=c++2a ./main.cc.
#include <iostream>
#include <concepts>
using namespace std;
template<std::regular_invocable F>
auto call_with_regular_invocable_constraint(F& f){
return f();
}
template<std::invocable F>
auto call_with_invocable_constraint(F& f){
return f();
}
class adds_one {
int state{0};
public:
int operator()() {
state++;
return state;
}
};
int main()
{
auto immutable_function_object([]() { return 1; });
adds_one mutable_function_object;
// I would expect only first three will be compiled and the last one will fail to compile because the procedure is
// not regular (that is does not result in equal outputs given equal inputs).
cout << call_with_invocable_constraint(immutable_function_object) << endl;
cout << call_with_invocable_constraint(mutable_function_object) << endl;
cout << call_with_regular_invocable_constraint(immutable_function_object) << endl;
cout << call_with_regular_invocable_constraint(mutable_function_object) << endl; // Compiles!
}
Output of the program:
1
1
1
2

From the reference:
Notes
The distinction between invocable and regular_invocable is purely semantic.
This means that there is no way for the compiler to enforce the distinction through the concepts system, since that can only check syntactic properties.
From the introduction to the concepts library:
In general, only the syntactic requirements can be checked by the compiler. If the validity or meaning of a program depends whether a sequenced of template arguments models a concept, and the concept is satisfied but not modeled, or if a semantic requirement is not met at the point of use, the program is ill-formed, no diagnostic required.
Hypothetically, we could write:
template< class F, class... Args >
concept regular_invocable = invocable<F, Args...> &&
requires(F&& f, Args&&... args) {
auto prev = f;
std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
assert(f == prev);
// TODO assert that `args` are unchanged
// TODO assert that invoking `f` a second time gives the same result
};
However, this would not actually test that the assertion holds, since a requires clause is not invoked at run time but only checked at compile time.

regular_invocable tells the user of the function that it will assume, that the result calling that regular_invocable function with the same value of the arguments will result in the same return value, and might cache that result due to that.
Caching the result could either be done by the function that expects regular_invocable or the compiler could use that information to optimize away multiple function calls to the regular_invocable function when the value of the arguments stay the same. So right now it can be seen as documentation and compiler hint.
Similar to const_cast it might not always be possible for the compiler to check if it is valid. Due to that and because there is currently not attribute/keyword in the standard to mark a function to always return the same value, there is right now no way to enforce at compile time that the function passed regular_invocable really matches that requirement.

Related

Why even i am instantiating template parameter at runtime but i am getting expected output instead of error ie. we cannot expand template at runtime?

As I know that templates are expanded at compile time but in below example i am deciding or doing
template instantiation at runtime depending on user input but still i am getting expected output.how this running?
can someone explain me
#include <iostream>
using namespace std;
template<typename T>
class Demo
{
T Value = 20.67;
public:
void print(T val)
{
std::cout << "value :" << val << std::endl;
}
T getValue()
{
return Value;
}
};
int main()
{
int a;
std::cout << "Enter value for a :";
std::cin >> a;
if(a == 10)
{
Demo<int> demoObj1;
demoObj1.print(demoObj1.getValue());
}
else
{
Demo<float> demoObj2;
demoObj2.print(demoObj2.getValue());
}
}
//output:
Enter value for a :10
value :20
and Enter value for a :7
value :20.67
At compile time, both templates are created. There exists code in your compiled program for both branches. At runtime you are simply selecting which branch to execute.
The compiler sees the two branches of code and realizes that it cannot determine which branch will be taken at compile time, so it will generate code for both branches. If the compiler can determine at compile time that a branch cannot possibly be taken, a compiler may optimize it away. A simple situation is with the following:
if (4 < 5) {
Demo<int> demoObj1;
demoObj1.print(demoObj1.getValue());
} else {
Demo<float> demoObj2;
demoObj2.print(demoObj2.getValue());
}
In this case, the compiler can see that the second branch will never get executed. The compiler will initially compile both branches, but then it may discard the second branch from the final executable. Whether or not the compiler does this depends on the compiler implementation and compilation flags.
You can force the compiler to reject unused branches with if constexpr. Consider the following example:
if constexpr (4 < 5) {
Demo<int> demoObj1;
demoObj1.print(demoObj1.getValue());
} else {
Demo<float> demoObj2;
demoObj2.print(demoObj2.getValue());
}
All that was changed is that this example uses if constexpr. In this example, the second branch will NOT be fully compiled (it is still checked for correct syntax, but assembly generation is not done). Code for the second branch will not exist in the executable.
Both Demo<int> and Demo<float> will be instantiated compile time as you're using a normal(non-constexpr) if, else instead of constexpr if.
On the other hand, if you were to use constexpr if then only one of Demo<int> or Demo<float> would've been instantiated. Note that in this example we can't use constexpr if since the input is taken from user.

Can consteval functions from different translation units interfere?

I am trying to dig into implications of a function being inline and stumbled upon this issue. Consider this small program (demo):
/* ---------- main.cpp ---------- */
void other();
constexpr int get()
{
return 3;
}
int main()
{
std::cout << get() << std::endl;
other();
}
/* ---------- other.cpp ---------- */
constexpr int get()
{
return 4;
}
void other()
{
std::cout << get() << std::endl;
}
When compiled without optimizations, the program yields the following output:
3
3
Which might be not what we want, but at least I can explain it.
The compiler is not required to compute results of constexpr functions on compile time, so it decided to postpone it to runtime.
constexpr on functions implies inline
Our get() functions happened to have different implementations
We did not declare get() functions static
The linker must chose only one implementation of the get() function
And it so happened that the linker chose get() from main.cpp, which returned 3.
Now to the part I don't get. I simply changed get() functions from constexpr to consteval. Now the compiler is required to compute the value during compile time, i.e. before the link time (right?). I'd expect get() functions not to be present in object files at all.
But when I run it (demo), I have exactly the same output! How can this be?.. I mean yes, I understand that this is undefined behavior, but this is not the point. How come that the values that should have been computed on compile time interfered with other translation unit?
UPD: I am aware that this feature is listed as unimplemented in clang, but the question is applicable anyway. Is a conformant compiler allowed to exhibit such a behavior?
A program with two definitions of the same inline function is an ill-formed program, no diagnostics required.
The standard places no requirements on the runtime or compile-time behavior of an ill-formed program.
Now, there is no "compile time" in C++ as you are imagining it. While almost every C++ implementation compiles files, links them, builds a binary, then runs it, the C++ standard tip-toes around this fact.
It talks about translation units, and what happens when you put them together into a program, and what that program's runtime behaviour is.
...
In practice, your compiler could be building a map from symbol to some internal structure. It is compiling your first file, and then in the second file it is still accessing that map. A new definition of the same inline function? Just skip it.
Second, your code must produce a compile time constant expression. But a compile time constant expression is not an observable property in the context where you used it, and there are no side effects to doing it at link or even run time! And under as-if there is nothing preventing that.
consteval is saying "if I run this and the rules that permit it being a constant expression are violated, I should error rather than fall back on non-constant expression". This is similar to "it must be run at compile time", but it is not the same.
To determine which of these is happening, try this:
template<auto x>
constexpr std::integral_constant< decltype(x), x > constant = {};
now replace your print lines with:
std::cout << constant<get()> << std::endl;
this makes putting off the evaluation to run/link time as impractical.
That will distinguish between the "compiler is being clever and caching get" from "compiler is evaluating it later at link time", because determining which ostream& << to call requires instantiating the type of constant<get()>, which in turn requires evaluating get().
Compilers tend not to defer overload resolution to link time.
The requirement for a consteval function is that every call to it must produce a constant expression.
Once the compiler satisfies itself that a call does produce a constant expression, there's no requirement that it must not codegen the function and call it at run time. Of course, for some consteval functions (like those envisioned for reflection) it had better not do that (at least if it doesn't want to put all its internal data structures into the object file), but that's not a general requirement.
Undefined behavior is undefined.
The answer to this is that it's still an ODR violation, no matter if the function is a constexpr or consteval. Maybe with a particular compiler and a particular code you may get the answer you're expecting, but it's still ill formed, no diagnostic required.
What you could do is to define them in anonymous namespaces:
/* ---------- main.cpp ---------- */
void other();
namespace {
constexpr int get()
{
return 3;
}
}
int main()
{
std::cout << get() << std::endl;
other();
}
/* ---------- other.cpp ---------- */
namespace {
constexpr int get()
{
return 4;
}
}
void other()
{
std::cout << get() << std::endl;
}
But even better, simply use modules:
/* ---------- main.cpp ---------- */
import other;
constexpr int get()
{
return 3;
}
int main()
{
std::cout << get() << std::endl; // print 3
other();
}
/* ---------- other.cpp ---------- */
export module other;
constexpr int get() // okay, module linkage
{
return 4;
}
export void other()
{
std::cout << get() << std::endl; // print 4
}

Fold expression vs compile recursion

In c++17 we have fold expression which can greatly simplify code that could otherwise be implemented using compiler-recursion and SFINAE or overloading.
For example, in the following code
#include <iostream>
#include <utility>
template<typename ...Args>
void printer(Args&&... args) {
(std::cout << ... << args) << '\n';
}
void printer_cpp11() { }
template <typename First, typename ...Args>
void printer_cpp11(First&& first, Args&&... args)
{
std::cout << first;
printer_cpp11(std::forward<Args>(args)...);
}
int main()
{
printer(3, 4, "hello");
std::cout << std::endl;
printer_cpp11(3, 4, "hello");
return 0;
}
the c++17 function printer (taken from cpp reference) does exactly the same job as its c++11 version printer_cpp11.
At compile-time, several overloads of the function printer_cpp11 are generated, whereas a single function printer is needed using fold expression.
Is there an advantage in terms of performance in using fold expressions over the c++11-style? Or can one assume that the compiler inlines all the overloads of printer_cpp11, creating code with equivalent performance?
Both versions would lead to the same codegen due to inlining, so run-time performance is exactly the same: https://gcc.godbolt.org/z/VIHTvZ (code cleaned of streams clutter).
However, compilation times and memory usage are expected to be way better with fold expressions than with recursive instantiations, and because of that, fold expression are generally preferred. Not to mention they are also provide for cleaner and easier to reason about code.
Just to add to #SergeyA's answer you can alleviate the need for the recursion and the empty function in the c++11 version by doing something like...
template <typename ...Args>
void printer_cpp11_norecursion( Args&&... args)
{
using do_ = int[];
do_{0,
(std::cout << args,0)...
};
}
Which should generate the same results as both of the other versions (https://gcc.godbolt.org/z/hyAyiz) with possibly better compile times on c++11.
The compiler will create a new instance of printer for each call with different arguments and in the function will unfold the operator<< calls:
https://godbolt.org/z/Zz9Ik9
You can also see what happens here: https://cppinsights.io/
But ultimately - measuring will reveal if it leads to a performance gain.

Getting active value in std::visit without knowing which value is active

I want to get the active value in a std::variant without knowing which one is active. I thought i could write a template visitor and use std::visit but it doesn't work.
#include <variant>
#include <string>
#include <iostream>
struct Visit_configuration {
template<typename Data_type>
Data_type operator()(Data_type& t) const
{
return t;
}
};
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::cout << std::visit(Visit_configuration(), v); // expect "hello"
std::cin.get();
}
MSVC doesn't compile and throws:
error C2338: visit() requires the result of all potential invocations
to have the same type and value category (N4741 23.7.7
[variant.visit]/2).
note: see reference to function template instantiation 'int
std::visit&,0>(_Callable
&&,std::variant &)' being compiled
So how to fix this?
edit: I want to use the obtained value maybe also for other so putting cout in the template isn't what im looking for.
Ask yourself the question:
What is the return type of std::visit if you don't know what part of the variant is active?
That is the question that the compiler must answer. And the answer can't be "it depends" - you (as in, the compiler) must decide on exactly one type at compile-time. The visit call cannot possibly return different types at runtime.
If you want to work with different types "at runtime", you must be in a function templated on the type you want to work with. In other words, there must be different functions (or function template instantiations) to handle the "write an int to cout" and "write a string to cout" cases. You cannot do this in the same (non-templated) function.
The straightforward solution here is thus to put the std::cout << into your templated visitor function - that's the point of visiting: Specifying what is supposed to happen in each case.
If you want to "use the obtained value maybe also for [some] other [purpose]", then that "other purpose" should also be part of the/a visitor. Only then can you have that "other purpose" handle the different cases at once (e.g. in a templated function). Otherwise you must decide at compile-time already which type shall be used - the compiler is not going to leave that choice open for later (run time).
Return type of visitor function should be identical.
Create printer visitor instead:
struct PrinterVisitor {
template<typename T>
void operator()(const T& t) const
{
std::cout << t;
}
};
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::visit(PrinterVisitor{}, v); // expect "hello"
}
And in your case, you can even have lambda:
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::visit([](const auto& t){std::cout << t;}, v); // expect "hello"
}

How to check that template's parameter type is integral?

In the description of some std template function I saw something like:
if the template parameter is of integral type, the behavior is such and such.
otherwise, it is such and such.
How can I do a similar test? Perhaps dynamic_cast?
Since the function I write is for my personal use I can rely on myself to supply only correct parameters, but why miss a chance to learn something? :)
In addition to the other answers, it should be noted that the test can be used at runtime but also at compile-time to select the correct implementation depending on wether the type is integral or not:
Runtime version:
// Include either <boost/type_traits/is_integral.hpp> (if using Boost)
// or <type_traits> (if using c++1x)
// In the following, is_integral shoudl be prefixed by either boost:: or std::
template <typename T>
void algorithm(const T & t)
{
// some code
if (is_integral<T>::value)
{
// operations to perform if T is an integral type
}
else
{
// operations to perform if T is not an integral type
}
// some other code
}
However, this solution can be improved when the implementation of the algorithm greatly depends on the test. In this case, we would have the test at the top of the function, then a big then block and a big else block. A common approach in this case is to overload the function and make the compiler select the correct implementation using SFINAE. An easy way to do this is to use boost::enable_if:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>
template <typename T>
typename boost::enable_if<boost::is_integral<T> >::type
algorithm(const T & t)
{
// implementation for integral types
}
template <typename T>
typename boost::disable_if<boost::is_integral<T> >::type
algorithm(const T & t)
{
// implementation for non integral types
}
When invoking the algorithm function, the compiler will "select" the correct implementation depending on wether the template parameter is integral or not.
One possibility:
#include <type_traits>
#include <iostream>
struct trivial
{
int val;
};
int main()
{
std::cout << "is_integral<trivial> == " << std::boolalpha
<< std::is_integral<trivial>::value << std::endl;
std::cout << "is_integral<int> == " << std::boolalpha
<< std::is_integral<int>::value << std::endl;
std::cout << "is_integral<float> == " << std::boolalpha
<< std::is_integral<float>::value << std::endl;
return (0);
}
So you then use std::is_integral<> to determine the action.
If you are unable to use C++11 features, std::numeric_limits<T>::is_integer does the same thing as std::is_integral<T>::value, and is available with C++98.
Note that the 98 version is integer, not integral.
Boost.TypeTraits provides is_integral<>(), as described in another response, if your compiler does not yet support C++ features of the next standard.