When to use `static_assert` instead of SFINAE?

社会主义新天地 提交于 2019-12-20 08:49:25

问题


I have been using (and seen used) static_assert to flag undesired values of template parameter values. However, for all cases I came across it seems better and more elegant to disable those undesired values via SFINAE. For example

template<typename T,
         class = std::enable_if<std::is_floating_point<T>::value>::type>
struct Foo { ... };

instead of

template<typename T>
struct Foo {
  static_assert(std::is_floating_point<T>::value,
                "Foo<T>: T must be floating point :-(");
  ...
};

So my question: when to use static_assert instead of SFINAE and why?

EDIT

I think what I've learned so far is the following

1 SFINAE is a versatile and powerful but potentially very complicated tool that can be used for many tasks, including function overload resolution (which some seem to regard as its only purpose).

2 SFINAE can be used in a relatively simple way where ever static_assert can, except that it appears in the declaration (of a class or function) rather than its definition (or is is possible to insert a static_assert into, say, a class forward declaration?). That makes more verbatim and hence clearer code. However, because SFINAE is complicated, it tends to be harder to get right than a simple static_assert.

3 On the other hand static_assert has the benefit of a clearer compiler error message, which some seem to regard as the main purpose of either.


回答1:


I think static_assert is the right choice if you want to enforce that T is a floating point type. This method states your intent more clearly than the SFINAE solution.




回答2:


You use SFINAE, if you want another overload to be used, and static_assert if none of them would fit such parameter.




回答3:


static_assert makes the compilation fail. SFINAE allows you to remove one possible overload.




回答4:


For one, using SFINAE may lead to another overload being picked that was originally a worse match and wouldn't be considered.

And in the situation that there are other overloads, but non of them is viable, you get some nice things like this:

#include <type_traits>

void f(int){}
void f(bool){}
void f(char){}
void f(float){}
void f(long){}
void f(double){}
void f(short){}
void f(unsigned){}
void f(void*){}
void f(void (*)()){}

template<class C, class T = int>
using EnableIf = typename std::enable_if<C::value, T>::type;

template<class T>
struct sfinae_false : std::false_type{};

template<class T> 
void f(T&&, EnableIf<sfinae_false<T>> = 0){}

int main(){ struct X{}; f(X()); }

Output:

source.cpp: In function 'int main()':
source.cpp:23:30: error: no matching function for call to 'f(main()::X)'
source.cpp:23:30: note: candidates are:
source.cpp:3:6: note: void f(int)
source.cpp:3:6: note:   no known conversion for argument 1 from 'main()::X' to 'int'
source.cpp:4:6: note: void f(bool)
source.cpp:4:6: note:   no known conversion for argument 1 from 'main()::X' to 'bool'
source.cpp:5:6: note: void f(char)
source.cpp:5:6: note:   no known conversion for argument 1 from 'main()::X' to 'char'
source.cpp:6:6: note: void f(float)
source.cpp:6:6: note:   no known conversion for argument 1 from 'main()::X' to 'float'
source.cpp:7:6: note: void f(long int)
source.cpp:7:6: note:   no known conversion for argument 1 from 'main()::X' to 'long int'
source.cpp:8:6: note: void f(double)
source.cpp:8:6: note:   no known conversion for argument 1 from 'main()::X' to 'double'
source.cpp:9:6: note: void f(short int)
source.cpp:9:6: note:   no known conversion for argument 1 from 'main()::X' to 'short int'
source.cpp:10:6: note: void f(unsigned int)
source.cpp:10:6: note:   no known conversion for argument 1 from 'main()::X' to 'unsigned int'
source.cpp:11:6: note: void f(void*)
source.cpp:11:6: note:   no known conversion for argument 1 from 'main()::X' to 'void*'
source.cpp:12:6: note: void f(void (*)())
source.cpp:12:6: note:   no known conversion for argument 1 from 'main()::X' to 'void (*)()'
source.cpp:21:6: note: template<class T> void f(T&&, EnableIf<sfinae_false<T> >)
source.cpp:21:6: note:   template argument deduction/substitution failed:


来源:https://stackoverflow.com/questions/11984768/when-to-use-static-assert-instead-of-sfinae

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!