2

How can I write a C++ 20 concept requiring a member function template that takes a template argument that must be provided?

The goal of the following concept is to check that a type is tuple-like, except rather than checking std::get<I>(t) I want to check t.get<I>().

The following does not compile with g++ 10.1 using switch -std=c++2a.

#include <concepts> template <typename E> concept Tpl = requires(E const e, int idx) { { e.template get<idx>() } -> std::convertible_to<float>; }; 

if template is not used before get, it is of course does not compile (no angle braces, less/greater than operator).

8
  • I'm not sure what you're asking here - what do you mean by "explicitly stated argument type (note deduceable)"? Which argument are we talking about here? Commented Feb 20, 2021 at 18:02
  • 1
    I assume he wants some Tuple-Like class which has a member function wich behaves similar to std::get<Idx>(TupleLike) - but just as member function. Commented Feb 20, 2021 at 18:07
  • @Bernd If that's what OP wants, then OP can edit the question to say that. Or if they want something different, they should say something different. Commented Feb 20, 2021 at 18:13
  • yes like in std::tuple. Since there are no arguments to the member function the member function template parameter cannot be deduces. This is by design and the template parameter is stated with the call: e.get<idx>() in a in templated call, e.template get<idx>(). Commented Feb 20, 2021 at 18:18
  • 1
    Does it have to be a parametrized integer? Wouldn't checking for the validity of e.template get<(int)0>() be enough? Commented Feb 20, 2021 at 18:29

2 Answers 2

5

This:

template <typename E> concept Tpl = requires(E const e, int idx) { { e.template get<idx>() } -> std::convertible_to<float>; }; 

does not work because idx is not a constant expression, and you need it to be one in the context of calling get.

In order to do that, you need to pick a specific value of the index in order to check. The only one you can really pick is 0:

template <typename E> concept Tpl = requires (E const e) { { e.template get<0>() } -> std::convertible_to<float>; }; 

This will potentially match a function template get which has a template parameter of type int* or nullptr_t. If that's a concern, we can spell 0 in a more complicated way to avoid it being a null pointer constant, whether that's simply 1-1 or taking as a second "parameter" an object of type integral_constant<size_t, 0>:

template <typename E> concept Tpl = requires (E const e, std::integral_constant<size_t, 0> value) { { e.template get<value()>() } -> std::convertible_to<float>; }; 

If ultimately, the goal is to check that e.get<I>() works for all I from [0, tuple_size_v<E>), then you'll have to approach this a bit differently. In that context, you'll want the index you're checking to be part of the concept itself. As in:

template <typename E, size_t I> concept tuple_like_impl = requires (E const e) { { e.template get<I>() } -> std::convertible_to<float>; }; 

And then build up a parameter pack of Is... such that you eventually construct a constraint like (tuple_like_impl<E, Is> && ...).

But that's a step you should take only if you actually need to.

Sign up to request clarification or add additional context in comments.

Comments

-1

To let it compile you could write it like:

template <typename E, int idx> concept Tpl = requires(E const e) { { e.template get<idx>() } -> std::convertible_to<float>; }; 

But tell us what you really want.

3 Comments

While your guess may be reasonable, and even correct some portion of the time, you should try and get clarity on what the OP means before answering the question.
Thanks, for your response - and I agree.
I do not want to add idx to the class template parameters, but to the function. The background: It is a simplified example of a concept for multivector expressions (expression template), where each expression shall provide coefficient access similar to that in tuple, but sparse. The return value type varies over the indices to allow to distinguish between compile time constants (special class instances that convert to values) or runtime computed vales. computed values.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.