27

Are there any disadvantages in the following (suggested!) syntax?

template< typename T >
void f() static_assert(std::is_same< T, int >::value)
{ ; }

instead of SFINAE (that looks like a crutch):

template< typename T, typename = typename std::enable_if< std::is_same< T, int >::value >::type >
void f() { ; }

or even worse:

template< typename T >
typename std::enable_if< std::is_same< T, int >::value >::type 
f() 
{ ; }

which prohibits using of auto deduction of result type.

Tomilov Anatoliy
  • 15,657
  • 10
  • 64
  • 169
  • 2
    `static_assert` is *not* SFINAE, it's an assertion of things that *must be true*. – Xeo Jun 07 '13 at 06:07
  • that is not a valid c++11 code – BЈовић Jun 07 '13 at 06:34
  • @BЈовић I know. It is just a proposal of possible syntax. – Tomilov Anatoliy Jun 07 '13 at 07:44
  • 1
    In the meantime, it's possible to be [more concise](https://web.archive.org/web/20140703021445/http://flamingdangerzone.com/cxx11/2012/06/01/almost-static-if.html). – Luc Danton Jun 07 '13 at 09:36
  • `static_assert` is _not_ a proposal, it is an accepted part of the C++11 standard. – Piotr99 Jun 07 '13 at 10:43
  • @Piotr99 "To use `static_assert` in such syntax" is definitely "proposal". My own proposal. – Tomilov Anatoliy Jun 07 '13 at 10:45
  • @Dukales Well, it's quite useless to propose a new syntax with a keyword that's already defined differently in the standard. – Piotr99 Jun 07 '13 at 11:00
  • 1
    @Piotr99, nonsense, it's not a problem if the new proposal uses the keyword in a context where it couldn't previously be used, because that doesn't conflict with or alter the meaning of existing code. For example using the C keyword `static` on class member in C++, or using `extern` for explicit instantiation declarations in C++11, or using `using` for type aliases in C++11, or using `auto` for type deduction in C++11, or using `inline` for namespaces in C++11, or using `mutable` in lambda expressions in C++11, or using `auto` for generic lambdas in C++14, etc. etc. – Jonathan Wakely Jun 07 '13 at 13:38
  • That first example of yours doesn't compile for me -- http://coliru.stacked-crooked.com/view?id=04d0b7c77ef70dbae87b9f16b63db802-3ac4366c03bbdf3b770d4e4edaa157c5 – David G Jun 07 '13 at 18:24
  • @0x499602D2 It's sad but it's true. Please reread the original __Q__. – Tomilov Anatoliy Jun 08 '13 at 03:35

2 Answers2

26

First of all, those are different, specifically they are not checked at the same time.

The critical difference is due to their application with regard to overload resolution. SFINAE will cull functions from the overload set, so that another function gets chosen (if any) whereas static_assert is applied after overload resolution and thus will give an error that will stop compilation.

Now, regarding your complaint, you can perfectly use auto and SFINAE:

// Ensure that T is int
template <typename T>
auto f() -> typename std::enable_if< std::is_same< T, int >::value >::type
{ ... }

// Only pick this overload if begin(c) and end(c) are available
template <typename T>
auto f(T const& c) -> decltype(begin(c), end(c), bool{}) { ... }

... and you can perfectly use SFINAE and automatic type deduction

template <typename T,
          typename = typename std::enable_if<std::is_same<T, int>::value>::type>
auto f() { ... }

template <typename T>
auto f(void* =
       typename std::enable_if<std::is_same<T, int>::value>::type*(0))
{ ... }
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 1
    But my question is about only the verbosity (and what to do with it) of a SFINAE statements in the form in which they are at the moment. – Tomilov Anatoliy Jun 07 '13 at 08:00
  • @Dukales: Ah, yes indeed it is verbose. You could potentially use template aliases for often used tests: `template using enable_if_same = std::enable_if::value>::type;` and then `template > auto f() { ... }` ... also note that real deduction of return types (like for lambdas) is on the plate for C++1y. – Matthieu M. Jun 07 '13 at 08:11
  • I'm especially interested in new C++ standard's features. Anyways, each SFINAE condition I mostly use once. Therefore aliases is not universal the solution. – Tomilov Anatoliy Jun 07 '13 at 08:19
  • @MatthieuM. are you sure about the static_assert not involving overload resolution? In a few cases adding static_assert made the code call a different overloaded version of a function. Perhaps it worked there because the overload was a non-template function? – peter karasev Apr 18 '14 at 05:30
  • @peterkarasev: I am sure, overload resolution is only based on the signature whilst `static_assert` appears in the implementation. Likewise, SFINAE is only based on immediate contexts (thus signatures/declarations). – Matthieu M. Apr 18 '14 at 06:35
6

Why would using static_assert be better than the Concepts Lite syntax?

template< typename T >
  void f() requires Int<T>()
  { }

or:

template< Int T >
  void f()
  { }
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • `static_assert` is only a proposal. I did not know about the existance of the ([proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3580.pdf)) `requires` keyword before. It looks like the solution. – Tomilov Anatoliy Jun 07 '13 at 09:08
  • @0x499602D2, yes, there's a fork of GCC that implements it, see http://concepts.axiomatics.org/~ans/. You'd need to define the `Int` constraint, e.g. `template constexpr bool Int() { return std::is_same< T, int >::value; }` – Jonathan Wakely Jun 14 '13 at 15:53
  • 1
    Forgive me if I'm wrong, but haven't concepts been shelved until C++20 now? – Pharap Aug 02 '17 at 21:25
  • @Pharap yes, but that doesn't change anything in the answer above, except that you don't need to use a fork of GCC any more. GCC 7 supports concepts, enabled by the `-fconcepts` command-line option. – Jonathan Wakely Aug 09 '17 at 16:29
  • @JonathanWakely It might change things if someone was just planning to use concepts lite until 'C++17 concepts' were introduced. That's a whole extra 3 years of being dependant on a compiler-specific extension. – Pharap Aug 09 '17 at 19:00
  • It's not just a compiler specific extension, it's based on the ISO TS. – Jonathan Wakely Aug 10 '17 at 19:04