C++ Logo


Advanced search

Re: A Generic Library for Compile-time Routing

From: Nicolas Lesser <blitzrakete_at_[hidden]>
Date: Wed, 08 May 2019 15:45:35 +0200
Mingxin Wang via Std-Proposals wrote:
> Hi folks,
> I would like to propose a generic library for compile-time routing.
> `if constexpr` and "SFINAE/Concepts based class/function template specialization" are generally used for compile-time routing in complex template libraries. However, according to my experience, they are not so easy to code, maintain or test. Therefore, I designed a template library specifically for compile-time routing with more usability, enabling template library based on this library to have more extendibility and testability.
> Please find the draft of the proposal here: https://raw.githubusercontent.com/wmx16835/my-stl/4889927d02056acd29f7f98afdbb87423878e970/doc/applicable_template_preview.pdf
> I am looking forward to your valuable comments.
> Thanks,
> Mingxin Wang

Some comments:

> Although if constexpr works at compile-time, this code is incorrect because it never compiles. For example, if std::to_string is applicable to a value of const T& but const T& is not convertible to std::string, there will be always be a compile error in the second if constexpr body.

No that's not true, since this exact problem is why if constexpr exists in the first place! There wouldn't be any difference to a normal if what you're saying were true.
Demo: https://godbolt.org/z/iSKSu0

> Therefore, if we want to solve this problem with function template overloads, it is required to use the Concepts and carefully design the constraints so that to avoid ambiguation

Yes that's true, but it's not *that* bad. You only need to negate other constraints if there is possible overlapping. For example, !is_primitive_v is not needed for is_container_v, nor is it needed for is_tuple_v and is_string_convertible.

You could even side step this issue by making a concept that has both and using that for an overload (e.g) for types that are a container and are convertible to string and then in it choosing the overload you want to call. Granted, this needs a concept + an overload for each combination, but is otherwise pretty clean. (IMO if constexpr is still the best way for this though).

template <typename T>
concept BothContainerStr = is_string_convertible<T> && is_container_v<T>;

template <typename T> requires BothContainerStr<T>
std::string my_to_string_impl(const T& value) { return my_to_string_impl_for_convert_to_string(value); }
// use my_to_string_impl_for_convert_to_string for both the above and the 'requires is_string_convertible' case.

> For example, if we want to make a default option rather than producing a compile error if all of the rules above does not apply, and return the string "<unknown>", we will need to write another overload set of my_to_string_impl contains ALL of the basic constraints:

Nope, you just need:

std::string my_to_string_impl(...) { /*...*/ }

since ... has the lowest priority in overload resolution.

Basically, we already have "Another Possible Solution in the Future" right now with C++17. The if constexpr way is wayy cleaner than the metaprogramming way that you propose IMO.

- Nicolas

Received on 2019-05-08 08:47:18