template <class Derived>
class base
{
public:
constexpr auto operator()()
const noexcept { return static_cast<const Derived&>(*this)(); }
};
class derived : public base<derived>
{
public:
constexpr auto operator()()
const noexcept { return 0; }
};
template <class A, class B>
class expr : public base<expr<A, B>>
{
const A m_a;
const B m_b;
public:
constexpr explicit expr(const A a, const B b)
noexcept : m_a(a), m_b(b) {}
constexpr auto operator()()
const noexcept { return m_a() + m_b(); }
};
template <class D1, class D2>
constexpr auto foo(const base<D1>& d1, const base<D2>& d2)
noexcept { return expr<base<D1>, base<D2>>{d1, d2}; }
int main()
{
constexpr auto d = derived{};
constexpr auto e = foo(d, d);
static_assert(e() == 0, "");
}
dGVtcGxhdGUgPGNsYXNzIERlcml2ZWQ+CmNsYXNzIGJhc2UKewpwdWJsaWM6Cgljb25zdGV4cHIgYXV0byBvcGVyYXRvcigpKCkKCWNvbnN0IG5vZXhjZXB0IHsgcmV0dXJuIHN0YXRpY19jYXN0PGNvbnN0IERlcml2ZWQmPigqdGhpcykoKTsgfQp9OwoKY2xhc3MgZGVyaXZlZCA6IHB1YmxpYyBiYXNlPGRlcml2ZWQ+CnsKcHVibGljOgoJY29uc3RleHByIGF1dG8gb3BlcmF0b3IoKSgpCgljb25zdCBub2V4Y2VwdCB7IHJldHVybiAwOyB9Cn07Cgp0ZW1wbGF0ZSA8Y2xhc3MgQSwgY2xhc3MgQj4KY2xhc3MgZXhwciA6IHB1YmxpYyBiYXNlPGV4cHI8QSwgQj4+CnsKCWNvbnN0IEEgbV9hOwoJY29uc3QgQiBtX2I7CnB1YmxpYzoKCWNvbnN0ZXhwciBleHBsaWNpdCBleHByKGNvbnN0IEEgYSwgY29uc3QgQiBiKQoJbm9leGNlcHQgOiBtX2EoYSksIG1fYihiKSB7fQoKCWNvbnN0ZXhwciBhdXRvIG9wZXJhdG9yKCkoKQoJY29uc3Qgbm9leGNlcHQgeyByZXR1cm4gbV9hKCkgKyBtX2IoKTsgfQp9OwoKdGVtcGxhdGUgPGNsYXNzIEQxLCBjbGFzcyBEMj4KY29uc3RleHByIGF1dG8gZm9vKGNvbnN0IGJhc2U8RDE+JiBkMSwgY29uc3QgYmFzZTxEMj4mIGQyKQpub2V4Y2VwdCB7IHJldHVybiBleHByPGJhc2U8RDE+LCBiYXNlPEQyPj57ZDEsIGQyfTsgfQoKaW50IG1haW4oKQp7Cgljb25zdGV4cHIgYXV0byBkID0gZGVyaXZlZHt9OwoJY29uc3RleHByIGF1dG8gZSA9IGZvbyhkLCBkKTsKCXN0YXRpY19hc3NlcnQoZSgpID09IDAsICIiKTsKfQ==