How to express concepts over variadic template? - c++

I'd like to define a concept which just tuples with values of a specific type can satisfy.
Let's say for simplicity I just want to accept tuples just holding elements of a numeric type. How would I do this?
e.g.
std::tuple<int16_t, int32_t> // satisfies concept
std::tuple<std::string, double> // doesn't satisfy concept
The problem is I'd have to formulate something like "for_each_type". Also recursive concepts are not allowed.

Simply enough:
namespace impl {
template <class T>
struct is_tuple_of_integrals
: std::false_type { };
template <std::integral... Ts>
struct is_tuple_of_integrals<std::tuple<Ts...>>
: std::true_type { };
}
template <class T>
concept tuple_of_integrals = impl::is_tuple_of_integrals<T>::value;
I do wonder whether the intermediate trait can be omitted, but absent concept specializations I don't believe so.

My solution:
template<typename ... Args>
concept numeric_tuples = (std::is_integral_v<Args> && ...);
template<typename ... Args>
void foo(std::tuple<Args...> t) requires numeric_tuples<Args...> {
}
I used fold expression for the concept.

Related

Why is there no variable template template parameter?

I'm planning to create a variable template that takes (variable) template-template parameter and one typename:
template <template <typename> auto MetaPredicate, typename T>
constexpr bool has_predicate_v_ = requires {
{ MetaPredicate<T> } -> std::convertible_to<bool>;
}
Where the expectations are:
template <typename T>
struct dummy_01 {
inline static constexpr bool value = true;
};
template <typename T>
inline constexpr bool dummy_01_v = dummy_01<T>::value;
std::cout << std::boolalpha << has_predicate_v_<dummy_01_v, int> << '\n'; // true
But that doesn't work. It would be useful if they exist in standard.
Another case is to create a metafunction count_if:
template <typename Type, template <typename> bool Predicate>
struct count_if {
inline static constexpr size_t value = /** ... **/;
};
template <typename Type, template <typename> bool Predicate>
inline constexpr size_t count_if_v = count_if<Type, Predicate>::value;
// ...
count_if_v<std::tuple<int, double, void, size_t, unsigned short>,
std::is_integral_v> // yields to 3
There is also a proposal relating to my question: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2008r0.html
Why are there currently no variable template-template parameters/arguments?
What is the status of the proposal?
Are there any possible alternatives for variable template-template parameters/arguments?
You already linked to the proposal, so you’ve largely answered the question yourself. You might not know about the paper tracker that can answer the “status” question; it says that more motivating examples are sought (which might very well have been delayed by the pandemic), so maybe you should contribute yours!
As for alternatives, the usual one is to key on the trait rather than the helper variable template. Obviously new code might have to wrap a (foundational) variable template with a helper trait class template to take advantage of this, but it works.
To extend #DavisHerring's answer: I think there is little use of it: I don't really see the advantage of using the helper variable template instead of the trait directly. Here is e.g. what I would do for your two examples:
In C++20 I would actually write a concept
template <template <typename> class Predicate, typename T>
concept is_predicate = requires {
std::same_as<decltype(Predicate<T>::value), bool>;
};
that makes sure that a given predicate has a static bool member variable value. Before that you might additionally use std::enable_if instead or not use SFINAE at all.
Example 1:
template <template <typename> class MetaPredicate, typename T>
requires is_predicate<MetaPredicate, T>
constexpr bool has_predicate_v_ = requires {
std::same_as<decltype(MetaPredicate<T>::value), bool>;
};
and then call it with the trait has_predicate_v_<dummy_01, int> instead of the alias.
Try it here
Example 2:
template <template <typename> class Predicate, typename... Ts>
requires (is_predicate<Predicate, Ts> && ...)
struct count_if {
inline static constexpr size_t count = ((Predicate<Ts>::value == true ? 1 : 0) + ...);
};
and again call it with the trait std::is_integral instead: count_if<std::is_integral, int, double>::count.
Try it here

Can I pattern-match a type without writing a custom trait class?

Since C++20 concepts aren't standardized yet, I'm using static_assert as a makeshift concept check, to provide helpful error messages if a type requirement isn't met. In this particular case, I have a function which requires that a type is callable before getting its result type:
template <typename F, typename... Args>
void example() {
static_assert(std::is_invocable_v<F, Args...>, "Function must be callable");
using R = std::invoke_result_t<F, Args...>;
// ...
}
In addition, I require that the callable's result must be some kind of std::optional, but I don't know what type the optional will hold, so I need to get that type from it:
using R = // ...
using T = typename R::value_type; // std::optional defines a value_type
However, this will fail if type R doesn't have a value_type, e.g. if it's not a std::optional as expected. I'd like to have a static_assert to check for that first, with another nice error message if the assertion fails.
I could check for an exact type with something like std::is_same_v, but in this case I don't know the exact type. I want to check that R is some instance of std::optional, without specifying which instance it must be.
One way to do that is with a helper trait:
template <typename T>
struct is_optional { static constexpr bool value = false; };
template <typename T>
struct is_optional<std::optional<T>> { static constexpr bool value = true; };
template <typename T>
constexpr bool is_optional_v = is_optional<T>::value;
…and then I can write:
static_assert(is_optional_v<R>, "Function's result must be an optional");
That works, but it seems a little awkward to pollute my namespace with a helper trait just for a one-off check like this. I don't expect to need is_optional anywhere else, though I can imagine possibly ending up with other one-off traits like is_variant or is_pair too.
So I'm wondering: is there a more concise way to do this? Can I do the pattern matching on instances of std::optional without having to define the is_optional trait and its partial specialization?
Following the suggestion by several respondents, I made a re-usable trait:
template <typename T, template <typename...> typename Tpl>
struct is_template_instance : std::false_type { };
template <template <typename...> typename Tpl, typename... Args>
struct is_template_instance<Tpl<Args...>, Tpl> : std::true_type { };
template <typename T, template <typename...> typename Tpl>
constexpr bool is_template_instance_v = is_template_instance<T, Tpl>::value;
…so that I can write:
static_assert(is_template_instance_v<R, std::optional>, "Function's result must be an optional");
This is just as many lines and declarations as the is_optional trait, but it's no longer a one-off; I can use the same trait for checking other kinds of templates (like variants and pairs). So now it feels like a useful addition to my project instead of a kluge.
Can I do the pattern matching on instances of std::optional without having to define the is_optional trait and its partial specialization?
Maybe using implicit deduction guides for std::optional?
I mean... something as
using S = decltype(std::optional{std::declval<R>()});
static_assert( std::is_same_v<R, S>, "R isn't a std::optional" );
Explanation.
When R is std::optional<T> for some T type, std::optional{r} (for an r value of type R) should call the copy constructor and the resulting value should be of the same type R.
Otherwise, the type should be different (std::optional<R>).
The following is a full compiling example.
#include <iostream>
#include <optional>
template <typename T>
bool isOptional ()
{
using U = decltype(std::optional{std::declval<T>()});
return std::is_same_v<T, U>;
}
int main ()
{
std::cout << isOptional<int>() << std::endl; // print 0
std::cout << isOptional<std::optional<int>>() << std::endl; // print 1
}
Anyway, I support the suggestion by super: create a more generic type-traits that receive std::option as template-template argument.

Concept to check for variadic template function

With C++20 and concepts around the corner I wondered if it will be possible to write a concept to check if a Type has a function with a certain name which takes any number of arbitrary arguments.
Take the following code for example (with GCC's current concept TS syntax):
template <typename T>
concept bool Initializable = requires(T t) {
{ t.init() } ->void;
};
struct S {
void init() {}
};
static_assert(Initializable<S>);
The concept Initializable checks if a Type implements a void init() function. Now lets assume there is another Type which also has an init function but one which requires arguments, e.g. an int:
struct T {
void init(int) {}
};
Now in this case the static assertion would fail.
Is there any way to make the Initializable concept ignore the function arguments? This example might seem rather derived, but for something like a generic serializer there might be use-cases for such a concept.
There is a type trait for that, std::is_member_function_pointer. But if you want that the return type is void too, then you can do both at the same time:
template <typename>
struct mptr_returns_void : std::false_type {};
template <typename T, typename ...Args>
struct mptr_returns_void<void(T::*)(Args...)> : std::true_type {};
template <typename T>
concept Initializable = mptr_returns_void<decltype(&T::init)>::value;

Extracting a tuple of value_type from a tuple of containers in C++11

I have a function with a template parameter which I know to be a std::tuple of several standard C++ containers of varying element types.
How can I extract, out of this, a type that is a std::tuple of the element types?
For example, suppose I have the following function
template <typename TupOfCtrs>
void doStuff(const TupOfCtrs& tupOfCtrs) {
using TupOfElements = /*extract a tuple type by applying CtrT::value_type to each container in tupOfCtrs and combining the results into an std::tuple*/;
MyHelperClass<TupOfElements> helper;
}
and I know it is being called like this:
std::list<Foo> l {/*...*/};
std::vector<Bar> v {/*...*/};
std::deque<Baz> d {/*...*/};
auto tup = std::make_tuple(l, v, d);
In this case, I want the TupOfElements helper type to be defined as std::tuple<Foo, Bar, Baz>.
Note that I do not need to actually create the tuple, only to get its type.
How can this be achieved, possibly using the Boost::Fusion library?
You can do this even in a more simple manner without Boost Fusion like this:
// Template which takes one type argument:
template <typename Tuple> struct TupOfValueTypes;
// Only provide a definition for this template for std::tuple arguments:
// (i.e. the domain of this template metafunction is any std::tuple)
template <typename ... Ts>
struct TupOfValueTypes<std::tuple<Ts...> > {
// This definition is only valid, if all types in the tuple have a
// value_type type member, i.e. the metafunction returns a type only
// if all types of the members in the std::tuple have a value_type
// type member, and a std::tuple can be constructed from these:
using type = std::tuple<typename Ts::value_type...>;
};
template <typename TupOfCtrs>
void doStuff(const TupOfCtrs& tupOfCtrs) {
using TupOfElements = typename TupOfValueTypes<TupOfCtrs>::type;
// ...
}
But it is of course easier to specify doStuff for the std::tuple explicitly:
template <typename ... Ts>
void doStuff(const std::tuple<Ts...> & tupOfCtrs) {
using TupOfElements = std::tuple<typename Ts::value_type...>;
// ...
}
PS: Also note, that in many cases if you need to just have a list of types, the std::tuple class is an overkill, and might slightly hurt compilation times. Personally, I've always instead used a simple TypeList struct:
template <typename ... Ts> struct TypeList
{ using type = TypeList<Ts...>; };
If you want doStuff to take a std::tuple, make that explicit:
template <class... Ts>
void doStuff(std::tuple<Ts...> const& tupOfCtr) { ... }
Once you have that parameter pack, it's just a matter of pulling out the value_type:
template <class... Ts>
void doStuff(std::tuple<Ts...> const& tupOfCtr)
{
using value_tuple = std::tuple<typename Ts::value_type...>;
// ...
}

c++ recursive template specialisation

I wrote an abstract container template class that should define numeric operators (unary + and -, binary +, - and *) if it make sens for the template parameter (that is, if it is a numeric type).
Then, I would like to apply those numeric operations on containers of containers of numeric values (and on containers of containers of containers of numeric values, and so on).
I wrote the following code. The (A) marker shows how I tried to solve the recursive specialization problem.
template <typename T>
struct is_numeric : public std::is_arithmetic<T>{};
template <typename T> /* (A) */
struct is_numeric<GenericContainer<T>> : public std::is_arithmetic<T>{};
/* Classic generic container for non-numeric base types */
template <typename T, bool isNumeric=false>
class BaseContainer : public GenericContainer<T> {};
/* Numeric container: +,-,* operations for numeric base types */
template <typename T>
class BaseContainer<T, true> : public NumericContainer<T> {};
/* Arithmetic base types should map on numeric containers */
template <typename T>
class Container : public BaseContainer<T, is_numeric<T>::value> {};
Then, in a test program, I have the following assertions:
/* Vector inherits from Container */
typedef Vector<int, 3> V3D;
ASSERT(is_numeric<int>::value); /* # => OK */
ASSERT(is_numeric<double>::value); /* # => OK */
ASSERT(is_numeric<V3D>::value); /* # => FAIL */
The two firsts assertions work as expected
Your solution fails for a very specific reason: a template type parameter specialization will match only the exact type, and not any derived type.
If you wish for derived types to also match, you need switch gears and use another strategy. In the age of constexpr switching to functions will let you use overloading resolution to your advantage (as one strategy among others):
// Basis
constexpr bool is_numeric_impl(...) { return false; }
template <typename T>
constexpr bool is_numeric(T const& t) { return is_numeric_impl(&t); }
// Specializations
template <typename T,
typename = std::enable_if<std::is_arithmetic<T>::value>::type>
constexpr bool is_numeric_impl(T const*) { return true; }
template <typename T>
constexpr bool is_numeric_impl(GenericContainer<T> const*) {
return is_numeric((T const*)nullptr);
}
The main benefit being that this solution is open-ended so that other people may reuse the same traits and add specializations; because it uses a white-list.
Boost's enable_if and type traits allow tricks like you need:
template <class T, class Enable = void>
struct is_numeric : public std::is_arithmetic<T> {};
template <class T>
struct is_numeric<T, typename enable_if<is_base_of<GenericContainer<T>, T> >::type>
: public std::is_arithmetic<T> {};
The solution employs SFINAE principle to compile the second version of is_numeric when the template parameter meets the criteria inside enable_if. Notice that the syntax of is_base_of is is_base_of<Base, Derived>. There is more explanation in Boost's enable_if documentation.
Since the relationships in your case are even more complicated, as David Rodriguez kindly mentioned, you should probably make it a bit differently:
template <template <class> class U, class T>
struct is_numeric<U<T>, typename enable_if<is_base_of<GenericContainer<T>, U<T> > >::type>
: public std::is_arithmetic<T> {};
And if you cannot use the libraries themselves, you can always use them as inspiration :)
Did you try :
template <typename T>
struct is_numeric : public std::is_arithmetic<T>{};
template <template<class...> class Container, typename T, typename... Rest>
struct is_numeric<Container<T, Rest...>> : public is_numeric<T>{};
Seems to work for me.
You need to define the is_numeric trait for each container, you cannot just use the base definition.
template <typename T, size_t N>
struct is_numeric< Vector<T,N> > : is_numeric< GenericContainer<T> > // *
{};
Also note that the definition of the is_numeric should be similar the one in the comment, not the one in the question. That is, you want to define is_numeric for a container in terms of whether the nested type is numeric or not (so that you can peel off the different layers).