[Dune-devel] PSA: please avoid implicit conversion integral_constant<bool, ...> to bool
Jö Fahlke
jorrit at jorrit.de
Mon Feb 20 13:10:54 CET 2017
Hi!
I've seen expression like `std::is_same<T1, T2>()` (or any other type
predicate) where the result is implicitly converted to `bool` pop up
throughout Dune for some time now. Please stop that; they can't work in all
cases, and when they break they lead to hard-to-diagnose errors.
I recommend picking whatever appears least ugly to you from the following
list, and to use it whenever you need the value of an `integral_constant`.
- `std::is_same<T1, T2>::value`
- `std::is_same<T1, T2>().value` or `std::is_same<T1, T2>{}.value`
- `std::is_same<T1, T2>()()` or `std::is_same<T1, T2>{}()`
- `(bool)std::is_same<T1, T2>()` or `(bool)std::is_same<T1, T2>{}` or other
explicit casts
At the very least, please use it whenever you deal with `integral_constant`
results of type predicates or type property queries.
Rationale
=========
Trick Question
--------------
In the following program, will the `static_assert()` trigger, or will the
program compile?
```c++
#include <tuple>
#include <type_traits>
int main() {
static_assert(!std::is_same<std::tuple<void>, int>(), "Strange...");
}
```
Spoiler
-------
You will get an error similar to the following:
```
g++ -Wall -std=c++14 -o test test.cc
In file included from test.cc:1:0:
/usr/include/c++/4.9/tuple: In instantiation of ‘struct std::_Head_base<0ul, void, false>’:
/usr/include/c++/4.9/tuple:231:12: required from ‘struct std::_Tuple_impl<0ul, void>’
/usr/include/c++/4.9/tuple:390:11: required from ‘class std::tuple<void>’
test.cc:5:54: required from here
/usr/include/c++/4.9/tuple:134:17: error: forming reference to void
constexpr _Head_base(const _Head& __h)
^
```
Explanation
-----------
`std::is_same` is a proper class template, not a typedef template, so `!` will
use ADL to find candidate functions implementing it. The set of namespaces
for ADL includes the set of namespaces associated with `std::tuple<void>`,
which in turn includes the set of namespaces associated with any base classes
of `std::tuple<void>`. To determine the base classes, `std::tuple<void>` must
be completed, but you can't have a complete class with a `void` data member or
(which triggers the error here) a constructor taking a `const void &`
parameter.
Occurance
---------
I last came across this when writing a unit test for `Dune::TypeList` and
associated utilites. `Dune::IsEmptyTypeList<T>` is a type predicate that is
supposed to tell you for any type `T` whether it is and empty typelist.
Except that if `T` is a class type, it needlessly tries to complete it, so
```
static_assert(!Dune::IsEmptyTypeList<std::tuple<void> >::value, "...");
```
does not work as intended. Even though I use `::value` here, because
`IsEmptyTypeList` uses the implicit conversion to `bool` internally.
Regards,
Jö.
--
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 811 bytes
Desc: Digital signature
URL: <https://lists.dune-project.org/pipermail/dune-devel/attachments/20170220/37bb606e/attachment.sig>
More information about the Dune-devel
mailing list