yohhoyの日記

技術的メモをしていきたい日記

std::is_convertible vs. std::convertible_to

C++標準ライブラリstd::is_convertibleメタ関数とstd::convertible_toコンセプトの超微妙な違い。本記事の内容はStackOverflowで見つけた質問と回答に基づく。

要約:

  • is_convertible<From, To>メタ関数:From型からTo型へ暗黙変換できることを検査する。
  • convertible_to<From, To>コンセプト:From型からTo型へ暗黙変換および明示変換できることを検査する。

暗黙変換は可能だが明示変換が許可されないケースで差異が生じる。ジェネリックライブラリの設計者大変すぎでしょ。

#include <concepts>
#include <type_traits>

struct From;
struct To {
  To() = default;
  // From→Toの明示変換を禁止
  explicit To(From) = delete;
};
struct From {
  // From→Toの暗黙変換は許可
  operator To() { return {}; }
};

static_assert( std::is_convertible_v<From, To> );
static_assert( !std::convertible_to<From, To> );

To to1 = From{};  // OK: 暗黙変換
To to2{From{}};   // NG: 明示変換

C++20(N4861) 18.4.4/p1, 20.15.6/p5より引用(下線部は強調)。

Given types From and To and an expression E such that decltype((E)) is add_rvalue_reference_t<From>, convertible_to<From, To> requires E to be both implicitly and explicitly convertible to type To. The implicit and explicit conversions are required to produce equal results.

template<class From, class To>
  concept convertible_to =
    is_convertible_v<From, To> &&
    requires(add_rvalue_reference_t<From> (&f)()) {
      static_cast<To>(f());
    };

The predicate condition for a template specialization is_convertible<From, To> shall be satisfied if and only if the return expression in the following code would be well-formed, including any implicit conversions to the return type of the function:

To test() {
  return declval<From>();
}

[Note: This requirement gives well-defined results for reference types, void types, array types, and function types. -- end note] Access checking is performed in a context unrelated to To and From. Only the validity of the immediate context of the expression of the return statement (8.7.3) (including initialization of the returned object or reference) is considered. [Note: The initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the "immediate context" and can result in the program being ill-formed. -- end note]

関連URL