39

According to en.cppreference.com (from what I can gather):

  • std::is_convertible is a trait class requiring types From & To to be such that a function with return type To that returns a From value can compile.
  • std::convertible_to is a concept requiring types From & To to be as explained above, AND such that an r-value reference of type From can be converted with static_cast<To>.

The requirement imposed by std::is_convertible seems relatively straight-forward. Conversely, the r-value reference casting requirement of std::convertible_to seems oddly specific for such a generic concept that is shown in simple examples for C++20 features.

Being a novice in C++, I could not quite understand some terminology and parts of the supplementary descriptions provided in both webpages and I cannot imagine the exact difference between the requirements of either.

Some inter-related questions:

  • What are the practical implications for types From & To of not only being constrained by std::is_convertible but also by the strange r-value reference casting requirement?
  • What kind of candidate types for From & To are additionally rejected by the r-value reference casting requirement?
  • Why might a programmer want to use either of std::is_convertible or std::convertible_to, instead of the other, as constraints for their function return types or parameter types (aside from just the convenience of concepts)?

A simpler explanation or an example would help. Thank you!

Monad
  • 680
  • 8
  • 15

1 Answers1

40

std::is_convertible<From, To> (the type trait) checks is type From is implicitly convertible to type To.

std::convertible_to<From, To> (the concept) checks that From is both implicitly and explicitly convertible to To. It's rare that this is not the case, such types are ridiculous, but it's nice in generic code to just not have to worry about that case.

One example:

struct From;
struct To {
    explicit To(From) = delete;
};
struct From {
    operator To();
};

static_assert(std::is_convertible_v<From, To>);
static_assert(not std::convertible_to<From, To>);
Barry
  • 286,269
  • 29
  • 621
  • 977
  • Agreed! I'd like to add that it can be important to consider a custom requires clause or concept instead (that, as an example, might make use of _just_ std::Is_convertible instead) when you know the exact requirements you need and can thus allow for more candidate types to be accepted without using a catch-all concept like convertible_to! – Monad Jun 29 '20 at 18:30
  • "checks that type `From` is implicitly convertible to type to" is a category error: types aren't convertible to types in C++ - despite that [the library specification says so all over the place](http://wg21.link/lwg3105) - _expressions_ are convertible to types. `is_convertible_v` and `is_convertible` both actually check that an expression `e` such that `decltype((e))` is `From` is convertible to type `To`. – Casey Jun 29 '20 at 19:28
  • 2
    +100 for "it's nice in generic code to just not have to worry about that case." - much of the point of the standard library concepts is to make it clear that we consider cases like this pathological by excluding them formally. – Casey Jun 29 '20 at 19:29
  • 3
    -0.1 for using `not` instead of `!` – user253751 Jun 30 '20 at 11:21
  • 1
    @Casey `add_rvalue_reference_t` :) We don't care about prvalue nonsense other than void... (Edit: actually, we want `remove_cv_t>` - LWG issue submitted) – T.C. Jul 03 '20 at 00:39