On Jun 2, 2015 10:03 AM, "Peter Dimov" <lists@pdimov.com> wrote:
Bruno Dutra wrote:
//traits example using a lazy backend
...
template<typename _> using test = /*...*/
...
template<template<typename...> class f, typename... args> using is_evaluable = /*...*/
static_assert(is_evaluable<test, void>::value, ""); static_assert(!is_evaluable<test, int>::value, ""); static_assert(!is_evaluable<test, void, int>::value, "");
Where is the laziness here? The user sees test<> (an alias),
is_evaluable<> (an alias), and the static asserts don't refer to anything else. That's the point, one stretches long lengths to provide laziness under the hood and yet deprives the end user to make direct use of it, despite the fact it allows for useful features, such as lazy branching.
If I add another metafunction (in my sense, i.e. a template alias)
template<class T> using test2 = test<std::decay_t<T>>;
that has no lazy test2_c backend, is_evaluable still works for it:
static_assert(is_evaluable<test2, void const volatile>::value, ""); static_assert(!is_evaluable<test2, int()>::value, ""); static_assert(!is_evaluable<test2, void, int>::value, "");
What you mean? std::decay<>::type is the lazy backend. That's actually an example of the point I'm trying to make here, std::decay_t<> is and should be provided only as a shorthand for its lazy counterpart, without, however, attempting to replace it, simply because it can't. That is, the lazy version remains available to the end users if needed. Bruno Dutra