最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - concept or trait to check for copy initialization - Stack Overflow

programmeradmin1浏览0评论

I'd like to check how and if an object of type A can be constructed from an object of type B.
I also want to distinguished between direct and copy initialization and thus wrote these concepts:

template<typename A, typename B>
concept can_direct_init_from = requires { A{std::declval<B>()}; };
template<typename A, typename B>
concept can_copy_init_from = requires { A a = std::declval<B>(); };

The first one, I think, is strictly equivalent to std::constructible_from but I don't know of a similar concept for the copy initialization case.
std::convertible_to does not seem to be used for a copy initialization (according to the corresponding traits, it is equivalent to testing a static_cast from B to A).

Besides my version is ill-formed:

error: expected primary-expression before 'a'

AFAU, I can not "declare" variable inside a `requires clause.

Is there a way to test for "is copy initializable from"? Possibly by fixing my concept?

I'd like to check how and if an object of type A can be constructed from an object of type B.
I also want to distinguished between direct and copy initialization and thus wrote these concepts:

template<typename A, typename B>
concept can_direct_init_from = requires { A{std::declval<B>()}; };
template<typename A, typename B>
concept can_copy_init_from = requires { A a = std::declval<B>(); };

The first one, I think, is strictly equivalent to std::constructible_from but I don't know of a similar concept for the copy initialization case.
std::convertible_to does not seem to be used for a copy initialization (according to the corresponding traits, it is equivalent to testing a static_cast from B to A).

Besides my version is ill-formed:

error: expected primary-expression before 'a'

AFAU, I can not "declare" variable inside a `requires clause.

Is there a way to test for "is copy initializable from"? Possibly by fixing my concept?

Share Improve this question asked Feb 6 at 14:15 OerstedOersted 2,5946 silver badges25 bronze badges 2
  • I don't think you can do that, but copy initialisation is also performed when passing argument by value to a function, so void can_copy_init_from_helper(A); and in concept requires(B b) { can_copy_init_from_helper<A>(b); }; seems to do the trick: godbolt.org/z/TsWrPGfeY – Yksisarvinen Commented Feb 6 at 14:32
  • std::convertible_to requires both implicit conversion and static_cast to be valid and expects them to have the same effect. This is usually more reasonable than just checking implicit conversion. – cpplearner Commented Feb 6 at 14:47
Add a comment  | 

2 Answers 2

Reset to default 5

Sounds like std::is_convertible_v<B, A>, a.k.a. std::convertible_to<B, A>. The way that's traditionally implemented is to put the conversion in a function argument:

template<class T> T produce();
template<class T> void consume(T);

template<class A, class B>
concept can_copy_init_from =
  requires { consume<A>(produce<B>()); };

There are traits in <type_traits> to handle it; you have:

  1. std::is_constructible<T, args...> for explicit constructor(conversion) calls. It accepts all conversion operators(explicit or not) for single argument initialization.
  2. std::is_convertible<from,to> for implicit conversions. Every eligible single-argument constructor(including constructors with default arguments) is a converting constructor(= conversion), and accepted by the trait.

For single argument direct initialization, all conversion constructors and conversion operators are considered.

For single argument aggregate/copy initialization, only implicit(none-explicit) are considered.

The above traits therefore, reflect the accepted syntax. They are generally defined via none-portable compiler intrinsics. But if you need to manually definie them:

template<typename T, typename ...Targs>
concept my_is_constructible = 
requires(Targs ...vargs)
{ T(static_cast<Targs>(vargs)...); };

template<typename from, to>
concept my_is_convertible = 
requires(from x, void(*f)(to))
{ (*f)(static_cast<from>(x)); };

The second trait only succeeds iff implicit conversion is available. The forwarding problem has a lot of corners to consider; I am trying to avoid complexity via a self-cast through static_cast, but it may need further consideration. Nevertheless, all such definitions implicitly cover destructability too(which must always be true anyway).

发布评论

评论列表(0)

  1. 暂无评论