无用知识研究:如何用decltype里的逗号表达式判断一个类里面有operator <号,并在编译时优雅给出提示,而不是一大堆不相干的模板信息
注意,这个例子并非sfinae,主要目的是为了在编译时给出一个优雅的问题提示。
Boost.Asio的作者的文章。
User-friendly compile errors for templates in C++0x
很多github的开源库里,static_assert在class里好像也是这么用的
#include <string>
#include <type_traits>
#include <array>struct B {
};////////////////////////////////
template<typename T>
auto less_than_test(const T* t) -> decltype(*t < *t, char(0)); //注意decltype用的是逗号表达式std::array<char, 2> less_than_test(...);namespace My
{template <typename T>class set{public:static_assert(sizeof(less_than_test((T*)0)) == 1, //如果没有operator <,那么这个size就是2"type T must provide operator<");};
}
int main()
{My::set<int> s0;My::set<B> s;//static_assert(HasBeginT<A>::value, "111");//static_assert(HasBeginT<B>::value, "222");return 1;
}编译时,提示只有优雅的:
error C2338: type T must provide operator<
还有个例子,为了说明检查函数是否符合要求的:
template <typename T>
auto read_handler_test(T* t)
-> decltype( (*t)(*(const error_code*)0, (const std::size_t)0), char(0));std::array<char, 2> read_handler_test(...);template <..., typename ReadHandler>
void async_read(..., ReadHandler handler)
{static_assert(sizeof(read_handler_test(&handler)) == 1,"ReadHandler type requirements not met");...
}decltype里的(*t)(*(const error_code*)0, (const std::size_t)0), char(0));
是个整体,意思是t是个函数(指针),hander应该满足类似于:
void handler(const error_code v1, const std::size_t v2)
一个参数不一定是这个形式,意思到了就行了。。。
这样的话,如果传进来的ReadHandler如果不符合这种声明,那么编译时就给出
ReadHandler type requirements not met的提示
还有个例子:
Detect operator support with decltype/SFINAE
#include <iostream>#include <type_traits>template<class T, typename = decltype( std::declval<T>() < std::declval<T>() /*这里假装"执行一下operator < "*/ ) >
std::true_type supports_less_than_test(const T&);std::false_type supports_less_than_test(...);template<typename T>
using supports_less_than = decltype(supports_less_than_test(std::declval<T>()));struct random_type{};int main()
{std::cout << supports_less_than<double>::value << std::endl; // prints '1'std::cout << supports_less_than<int>::value << std::endl; // prints '1'std::cout << supports_less_than<random_type>::value << std::endl; // prints '0'
}