- concepts[meta header]
- concept[meta id-type]
- std[meta namespace]
- cpp20[meta cpp]
namespace std {
template<class From, class To>
concept convertible_to =
is_convertible_v<From, To> &&
requires(add_rvalue_reference_t<From> (&f)()) {
static_cast<To>(f());
};
}
- add_rvalue_reference_t[link /reference/type_traits/add_rvalue_reference.md]
- is_convertible_v[link /reference/type_traits/is_convertible.md]
convertible_to
は、From
に指定された型および値カテゴリから型To
へ変換可能であることを表すコンセプトである。
このコンセプトを満たすためにはdeclval
<From>()
と同じ型と値カテゴリを持つオブジェクトが型To
へ暗黙的にも明示的にも変換可能であり、それら暗黙的および明示的な変換は同じ結果とならなければならない。
FromR = add_rvalue_reference_t<From>
として、説明のための関数test()
を以下のように定義する。
To test(FromR (&f)()) {
return f();
}
このf
は引数をとらずFromR
を返す関数であり、f()
の呼び出しは等しさを保持する。
このtest()
とFromR, To
について、以下の条件を満たす場合に限って型From, To
はconvertible_to
のモデルである。
- 次のどちらかを満たす
To
はオブジェクト型でもオブジェクトへの参照型でもないstatic_cast<To>(f())
とtest(f)
は等しい
FromR
がオブジェクトへの参照型ではない場合、次のどちらかを満たすFromR
が非const
右辺値参照型の場合、f()
の呼び出しによって参照されるオブジェクトの状態は、上記の式の実行の後で有効だが未規定となる- 標準ライブラリの型のオブジェクトは特に指定がない場合、ムーブされた後の状態は有効だが未規定となる
- それ以外の場合、
f()
の呼び出しによって参照されるオブジェクトは上記の式の実行によって変更されない
2つ目の条件内に出てくる「上記の式」とは、static_cast<To>(f())
とtest(f)
のこと。
#include <iostream>
#include <concepts>
struct convert_int {
operator int() { return 0; }
convert_int(int){}
};
struct convert_double {
explicit convert_double(double) {}
explicit operator double() { return 0.0; }
};
// 明示的な変換と暗黙的な変換で結果が異なる例
struct vague_convert {
operator int() { return -1; }
explicit operator double() { return 1.0; }
};
int main()
{
std::cout << std::boolalpha;
std::cout << "--- fundamental type ---\n";
std::cout << std::convertible_to<int, short> << std::endl;
std::cout << std::convertible_to<short, int> << std::endl;
std::cout << std::convertible_to<std::size_t, int> << std::endl;
std::cout << std::convertible_to<int, std::size_t> << std::endl;
std::cout << std::convertible_to<int, const int> << std::endl;
std::cout << std::convertible_to<const int, int> << std::endl;
std::cout << std::convertible_to<int, double> << std::endl;
std::cout << std::convertible_to<double, int> << std::endl;
std::cout << std::convertible_to<float, double> << std::endl;
std::cout << std::convertible_to<double, float> << std::endl;
std::cout << std::convertible_to<int*, const int*> << std::endl;
std::cout << std::convertible_to<const int*, int*> << std::endl;
std::cout << "\n--- program-defined type ---\n";
std::cout << std::convertible_to<convert_int, int> << std::endl;
std::cout << std::convertible_to<int, convert_int> << std::endl;
std::cout << std::convertible_to<convert_double, double> << std::endl;
std::cout << std::convertible_to<double, convert_double> << std::endl;
std::cout << std::convertible_to<vague_convert, int> << std::endl;
std::cout << std::convertible_to<vague_convert, double> << std::endl;
}
- std::convertible_to[color ff0000]
--- fundamental type ---
true
true
true
true
true
true
true
true
true
true
true
false
--- program-defined type ---
true
true
false
false
true
true
- C++20
- Clang: ??
- GCC: 10.1 [mark verified]
- Visual C++: 2019 Update 3 [mark verified]