Boost logo

Boost :

Subject: Re: [boost] [GSoC] [Boost.Hana] Formal review request
From: Roland Bock (rbock_at_[hidden])
Date: 2014-08-03 03:58:23


On 2014-08-02 23:57, pfultz2 wrote:
>> I would just like every library invoke a compile time assert whenever
>> > in instantiate a template with type arguments which won't work.
>> > Boost Concept Check can do this. In fact, maybe BCC is over kill.
>> > I seriously considered recommending making concept checking classes with
>> > just static_assert. But in the end I opted for recommending BCC.
> Yes, of course, static assertions can help improve error messages and its
> better than nothing, but it is not the same as template constraints.
True, but static_assert covers the following cases at least and is
really simple:

a) You have one implementation (class or function) and arguments are
either valid or not:

template<...>
struct X
{
    static_assert(check1, "failed check1");
    ...
};

b) You have one or more full or partial class specializations for
specific classes/templates/values:

Basically as above, but if you want to prohibited the default case or
certain specializations, here's a nice, minimalistic helper to do so [1]:

namespace detail
{
  template<typename... T>
    struct wrong
    {
      using type = std::false_type;
    };
}
template<typename... T>
  using wrong_t = typename detail::wrong<T...>::type;

It can be used to defer static_assert until a template is instantiated
which is an error since it is prohibited:
 

// disabled default case, slightly shortened from [2] template<typename
Context, typename T>
struct serializer_t
{
  static_assert(wrong_t<serializer_t>::value,
"missing serializer specialization");
};

// Any number of valid specializations like this [3]
template<typename Context, typename... Args>
struct serializer_t<Context, column_t<Args...>>
{
  // You could have static asserts here, too
};

// Or you can switch off certain cases [4]:
template<typename Lhs, typename Rhs, typename On>
struct serializer_t<sqlite3::serializer_t, join_t<outer_join_t, Lhs,
Rhs, On>>
{
   static_assert(::sqlpp::wrong_t<serializer_t>::value, "No support for
outer join");
};

static_assert is not sufficient for selecting overloads or if you have
several class specializations and need to select the correct one based
on concepts like ForwardIterator or so. In those cases, I would use
enable_if or similar (and wait for Concepts Lite).

In the sqlpp11 code, which enforces type constraints in pretty much
every template, enable_if is required in only about 7% of the templates.
Most of them are implementations of the constraint-checks.

Regards,

Roland

[1]: https://github.com/rbock/sqlpp11/blob/master/include/sqlpp11/wrong.h
[2]:
https://github.com/rbock/sqlpp11/blob/develop/include/sqlpp11/serializer.h
[3]: https://github.com/rbock/sqlpp11/blob/master/include/sqlpp11/column.h
[4]:
https://github.com/rbock/sqlpp11-connector-sqlite3/blob/develop/include/sqlpp11/sqlite3/serializer.h


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk