Is there any way to pass C++ concepts themselves? - c++

template<class S>
using Floating1 = std::is_floating_point<S>;
template<class S>
concept Floating2 = std::is_floating_point_v<S>;
You can pass Floating1...
template<template<class...> class F> struct TType {
template<class... S> using type = F<S...>;
};
using X = TType<Floating1>;
//...
template<class S> using Y = typename X::template type<S>;
So what about Floating2? You can call a function that distinguishes a Floating2 if you know that's what you're looking for, just like instantiating Floating1<S>; but how do you pass Floating2 like TType<Floating1>?
I highly suspect that it can't be done, any more than you can pass class or auto.
As a possible use case, functions like std::invoke have variants that let you specify a return type. It would be great if that return type could be a constrained auto. Can any function, template, etc. accept a concept, outside of concepts/requirements themselves?
Or you could write two helper functions, one using the concept and one not, for each and every concept you want to consider. There has to be a better way.

No, concepts can't be passed as template (or any other kind of) arguments.
As a possible use case, functions like std::invoke have variants that let you specify a return type. It would be great if that return type could be a constrained auto. Can any function, template, etc. accept a concept, outside of concepts/requirements themselves?
The caller of std::invoke can already achieve the exact same behavior that this would have at the call site, i.e.
SomeConcept auto ret = std::invoke(/*...*/);
This will produce an error if the return value doesn't satisfy SomeConcept. That's all a constraints on a return type of std::invoke would do as well.
I suspect this wasn't considered as a feature because there aren't any or many use cases that would actually profit over the current situation.

Related

Is it possible to determine if a callable is a predicate (i.e. returns bool)?

In an attempt to rewrite a predicate combinator like this
auto constexpr all = [](auto const&... predicates){
return [predicates...](auto const&... x){
return (predicates(x...) && ...);
};
};
(little generalization of this) in a way that it would give meaningful errors when fed with non-predicates/predicates with different arities/arguments, I started writing something like this:
template<typename T, typename = void>
struct IsPredicate : public std::false_type {};
template<typename T>
struct IsPredicate<T, std::enable_if_t<std::is_same_v<bool, return_type_of_callable_T>, void>>
: public std::true_type {};
and then I stared at it for a while... How do I even check what is the return type of a function, if I don't even know how to call it?
I see this:
I couldn't even pass decltype(overloaded_predicate_function) to IsPredicate, because template type deduction can't occur with an overloaded name,
even if I only talk of function objects, the problem of the first bullet point could apply to operator(), in case it is overloaded.
So my question is: is it even possible to determine the return type of an arbitrary callable?
I'm mostly interested in a C++17 answer, but, why not?, I'd also like to know what C++20's concept offer in this respect.
So my question is: is it even possible to determine the return type of an arbitrary callable?
No. You can only do this in very narrow circumstances:
the callable is a pointer to member data / pointer to member function
the callable is a pointer/reference to function
the callable is a function object with a single non-overloaded function call operator that is not a template and no conversion functions to function pointers/reference
That's it. If you have a function object whose call operator is either overloaded or a template, you can't really figure out what its return type is. Its return type could depend on its parameter type, and you may not have a way of knowing what the parameter types could be. Maybe it's a call operator template that only accepts a few specific types that you have no way of knowing about, but it is a predicate for those types?
The best you can do is defer checking until you know what what arguments are. And then C++20 already has the concept for you (predicate):
inline constexpr auto all = []<typename... Ps>(Ps const&... predicates){
return [=]<typename... Xs>(Xs const&... x)
requires (std::predicate<Ps const&, Xs const&...> && ...)
{
return (std::invoke(predicates, x...) && ...);
};
};
Note that you should use std::invoke to allow for pointers to members as predicates as well (and this is what std::predicate checks for).
You cannot determine the return type of a callable without specifying the argument types (usually done by providing actual arguments) because the return type could depend on the argument types. "decltype(potential_predicate)" won't work but "decltype(potential_predicate(args...))" is another matter.
The first will be the type of the callable itself (whether pointer-to-function or a class type or whatever) while the second will produce the return type of the callable expression.
Can't give you a C++17 answer, but since you also asked for concepts:
The requires expression states that the () operator is overloaded and returns a bool. I think a predicate in the classical sense takes two arguments, but the concept can be easily extended to fo fulfill that requirement as well.
template<typename T>
concept IsPredicate =
requires(T a) {
{ a() } -> std::same_as<bool>;
};

C++ concept isn't easy to use?

I needed to specify a concept for Messages - very simple as long as it has a typeTag static member - see below, I simply write - and I do not think I am supposed to write much more than this if concept is easy to use:
template <typename M>
concept MessageC = requires(M m) {M::typeTag;};
then I have trouble for a straightforward use:
template <MessageC Message>
void send(Message&& m){...}
The concept turns out to be not usable when Message is deduced to be Finish&, where Finish is actually a Message type. Finish&::typeTag is ill-formed as the g++ 9 compiler complains.
I could do things like remove_reference in the concept definition except I do not know that is the recommended way. Is C++ Concept meant to be simpler to use than that?
Thanks.
Your concept is best written this way:
template<typename M>
concept MessageC = requires { typename M::typeTag; };
i.e. you need typename for the dependent name, and there is no need for arguments in the requires expression.
When it comes to your actual question:
template<MessageC Message>
void send(Message&&) {}
is equivalent to:
template<typename Message>
void send(Message&&) requires MessageC<Message> {}
but, as you noted, Message is a forwarding reference, which can collapse to either lvalue or rvalue references.
Therefore, your function should read:
template<typename Message>
void send(Message&&) requires MessageC<std::remove_reference_t<Message>> {}
consistently with the language rules.
I could do things like remove_reference in the concept definition except I do not know that is the recommended way.
The standard does it plenty of times. It doesn't usually do this specifically for member typedefs and such, but that's because the standard typically uses traits classes to get "members" of a type, so that fundamental types could be used in those cases. Pointers don't have a value_type method, so the concepts library instead uses iterator/readable_traits.
Concepts are still C++; you can't just ignore rules of the language. Statements in concepts still must follow the rules of C++. A concept's template parameters work just like any other template parameters.
I end up writing the following to limit the typeTag static value within 2 bytes
template <typename M>
concept MessageC = std::remove_reference<M>::type::typeTag >= 0x0
&& std::remove_reference<M>::type::typeTag <= 0xffffu;

C++ template metaprogramming: how to deduce type in expression pattern

I am want a static check of the parameter type of lambdas. I've written this code below and it seems to produce the correct result.
struct B { };
auto lamBc = [](B const& b) { std::cout << "lambda B const" << std::endl; };
template<typename ClosureType, typename R, typename Arg>
constexpr auto ArgType(R (ClosureType::*)(Arg) const)->Arg;
template <typename T>
using ArgType_t = decltype(ArgType(&T::operator()));
// ArgType_t<lamBc> is "reference to B const"
However, I noticed that, for example, the standard library uses class template specialization to extract the referred-to type from a reference type in std::remove_reference. So I tried that approach and it also seems to produce the correct result.
template<typename L>
struct ArgType2;
template<typename ClosureType, typename R, typename Arg>
struct ArgType2<R (ClosureType::*)(Arg) const>
{
typedef Arg type;
};
template <typename T>
using ArgType2_t = typename ArgType2<decltype(&T::operator())>::type;
// ArgType2_t<lamBc> is also "reference to B const"
My questions are: Which is the standard way to extract types from a pattern expression? What are the trade-offs in either approach?
Both your approaches are valid, interchangeable and lead to the same result (deduce the type of the parameter lambda accepts).
For type traits it is required by the standard (see 23.15.1 Requirements) that:
A UnaryTypeTrait describes a property of a type. It shall be a class template that takes one template type argument and, optionally, additional arguments that help define the property being described. ...
A BinaryTypeTrait describes a relationship between two types. It shall be a class template that takes two template type arguments
and, optionally, additional arguments that help define the
relationship being described. ...
A TransformationTrait modifies a property of a type. It shall be a class template that takes one template type argument and, optionally, additional arguments that help define the modification. ...
I suppose that this requirement appeared mostly for historical reasons as decltype functionality was introduced after type traits had been proposed (and these type traits were based on type traits from boost which had been created even earlier, see, for example, this).
Also, note, that class templates are more flexible for general purpose type traits than the logic based on functions declarations and decltype.
The main point is that with C++11 and later in your particular case you are free to use the way which is the most convenient and reflects the programming logic better.
They are both "standard", the decltype() way is simply available in modern C++ variants, the PTS method was the only way to do this sort of things under the original C++ standard.

How to pass real type of auto into template

So I have something for example
auto a = getMyTuple();
which will eventually be real type of std::tuple<(some args)>
Now I want to store this in a class which has a template since I dont know the type yet. Something along the lines of
template<typename T>
class my_tuple
{
public:
T mt;
my_tuple(T t)
{
mt = t;
}
};
My question is, is there a way to get the type returned by auto, so I can pass it into the template class like
my_tuple<getType(a)> myTup(a);
That's what decltype is for:
my_tuple<decltype(a)> myTup(a);
You want decltype (since C++11):
my_tuple<decltype(a)> myTup(a);
You could implement a factory function that will construct your objects, the same way as std::make_tuple() constructs std::tuple.
(simplified version, see more plausible version in the link above or in your favorite standard library's source code)
template <typename T>
my_tuple<T> my_make_tuple(T t) {
return my_tuple<T>(t);
}
auto myTup = my_make_tuple(a);
Function call template argument deduction will figure out the types automagically, so you don't need to worry about explicit types anymore.
This is how they do it in standard library.
See this talk by Stephan T. Lavavej: Don’t Help the Compiler (towards the second half of it)
Update:
I think that the solutions with decltype posted around are ugly and error prone, because of the repetition of the variable name (violation of DRY principle). Also, decltype is unnecessary here as types can be deduced automatically with the use of a function wrapper. Finally, if your tuple would have 25 parameters will you write decltype 25 times? What if you accidentally mix the order of types and the order of parameters?

Getting Return Type of Callable Type in VS2010

I have a template class with a callable type-parameter <typename Callable>.
I know that Callable indeed creates a callable object, and is often a lambda.
In my particular case, I also know the number (arity) and type of arguments (just one).
How can I get the return type of this callable type Callable on VS2010?
See std::result_of.
Pretending the object is invoked with one int argument, you could do things like:
using return_type = typename std::result_of<Callable(int)>::type;
This isn't generally possible.
There are multiple ways to have callable types, including lambdas and structs that overload operator().
C++ does not have nearly the type of reflection that languages like C# do, and it is impossible to do with the tools that C++ offers.
If all you want is to store the result of that "callable" into a variable, then you can just use auto.
If you actually want to do stuff with the result based on its type, then this question might help.
Basically, add this to your code.
template <typename T, typename U>
struct same_type
{
static const bool value = false;
};
template <typename T>
struct same_type< T, T >
{
static const bool value = true;
};
Then, if you have auto result = func(param);, where func is of type Callable, you can check the type of result with the following:
if (same_type<decltype(result), int>().value)
{
// code, knowing that result is of type int
}
else if (same_type<decltype(result), const char*>().value)
{
// code, knowing that result is of type const char*
}
// else if ... etc.
I tried various approaches, but support for C++11 in VS2010 is only partial and most approaches simply didn't compile.
What did finally work (on VS2010) is the following:
// When arity is known
typedef decltype(callbackInstance0()) return_type0;
typedef decltype(callbackInstance1(argInstance)) return_type1;
Where callbackInstanceX is the actual callable object to be used and argInstance is the actual arg to be passed to callbackInstance.
Note that this is not a general solution (though sufficient in my case) because:
It cannot be used outside of a function where you don't have actual instances of these types, but only the types, as in the class definition;
The callable arity must be known.