C++ void_t
考虑如下代码:
#include <type_traits> #include <iostream> #include <vector> using namespace std; template <typename T, typename = void> struct RangeConcept : std::false_type {}; template <typename T> struct RangeConcept<T, std::void_t< decltype( std::declval<T >().begin() ), decltype( std::declval<T >().end() ) > > : std::true_type {}; template<typename Cont> void show( Cont c){ static_assert( RangeConcept< Cont >::value, "must be a range. means.. it has begin() and end()" ); }
int main() {
std::vector<int> vec{1,2,3,4,5}; show(vec);
}
这就是C++17带来的void_t神器。写个静态断言无比容易。手写个Concept检查也不再是C++库开发者的专利了。
配合SNINAE和enable_if ,如下:
template<typename T> void show(T& t, typename std::enable_if< RangeConcept<T>::value >::type* = 0){ std::cout << "I am a Range" << std::endl; } template<typename T> void show(T& t, typename std::enable_if< std::is_integral<T>::value >::type* = 0){ std::cout << "I am a others" << std::endl; } int main(){ std::vector<int> vec; int x=10; show(vec); }
参考:http://en.cppreference.com/w/cpp/types/void_t
原理:using引入类型别名
#include <iostream> template<int N,int M> struct add{ static constexpr int result = N + M; }; template<int M> using add8 = add<8,M>; int main(){ std::cout << add8<2>::result; }
C++17起,支持了变长模板参数
template<typename...Args> using void_t = void; int f(void_t<int,char>){} int f(void){} int main(){ f(); }
链接错误。原因在于void_t<int,char>等价于void,因此重定义了两次f();