使用SFINAE检测constexpr [英] Detecting constexpr with SFINAE
问题描述
我正在努力升级一些C ++代码以利用C ++ 11中的新功能。我有一个trait类与几个函数返回基本类型,这在大多数时候,但不总是,返回一个常量表达式。我想根据函数是否 constexpr
做不同的事情。我想出了以下方法:
template< typename Trait>
struct test
{
template< int Value = Trait :: f()>
static std :: true_type do_call(int){return std :: true_type(); }
static std :: false_type do_call(...){return std :: false_type(); }
static bool call(){return do_call(0); }
};
struct trait
{
static int f(){return 15; }
};
struct ctrait
{
static constexpr int f(){return 20; }
};
int main()
{
std :: cout< regular:<< test< trait> :: call()<< std :: endl;
std :: cout<< constexpr:< test< ctrait> :: call()<< std :: endl;
}
额外的 int
/ ...
参数是这样,如果两个函数在 SFINAE 后可用,第一个通过重载分辨率来选择。
使用 Clang 3.2 编译和运行此操作显示:
regular:0
constexpr:1
所以这看起来工作,但我想知道代码是否合法C ++ 11。
p> 注意:我在此处打开了一个问题,说明OPs代码是否实际有效。以下重写的示例将适用于任何情况。
但我想知道代码是否合法C ++ 11
这是,虽然可以考虑默认的模板参数有点不寻常。我个人喜欢下面的风格更好,这是类似于你(读:我)写一个trait到检查函数的存在< a>,只需使用非类型模板参数并省略 decltype
:
#include< type_traits>
命名空间详细信息{
template< int> struct sfinae_true:std :: true_type {};
template< class T>
sfinae_true<(T :: f(),0)> check(int);
template< class>
std :: false_type check(...);
} // detail ::
template< class T>
struct has_constexpr_f:decltype(detail :: check< T>(0)){};
说明时间〜
†,因为默认模板参数的实例化点是其函数模板的实例化点,在你的情况下,在 main
§14.6.4.1[temp.point] p2
如果一个函数模板[...]被调用,使用该函数模板的默认参数定义[...] ,默认参数的实例化点是函数模板[...]的实例化点。
它只是通常的SFINAE规则。
†至少我认为,这不是完全标准。
I'm working on upgrading some C++ code to take advantage of the new functionality in C++11. I have a trait class with a few functions returning fundamental types which would most of the time, but not always, return a constant expression. I would like to do different things based on whether the function is constexpr
or not. I came up with the following approach:
template<typename Trait>
struct test
{
template<int Value = Trait::f()>
static std::true_type do_call(int){ return std::true_type(); }
static std::false_type do_call(...){ return std::false_type(); }
static bool call(){ return do_call(0); }
};
struct trait
{
static int f(){ return 15; }
};
struct ctrait
{
static constexpr int f(){ return 20; }
};
int main()
{
std::cout << "regular: " << test<trait>::call() << std::endl;
std::cout << "constexpr: " << test<ctrait>::call() << std::endl;
}
The extra int
/...
parameter is there so that if both functions are available after SFINAE, the first one gets chosen by overloading resolution.
Compiling and running this with Clang 3.2 shows:
regular: 0
constexpr: 1
So this appears to work, but I would like to know if the code is legal C++11. Specially since it's my understanding that the rules for SFINAE have changed.
NOTE: I opened a question here about whether OPs code is actually valid. My rewritten example below will work in any case.
but I would like to know if the code is legal C++11
It is, although the default template argument may be considered a bit unusual. I personally like the following style better, which is similar to how you (read: I) write a trait to check for a function's existence, just using a non-type template parameter and leaving out the decltype
:
#include <type_traits>
namespace detail{
template<int> struct sfinae_true : std::true_type{};
template<class T>
sfinae_true<(T::f(), 0)> check(int);
template<class>
std::false_type check(...);
} // detail::
template<class T>
struct has_constexpr_f : decltype(detail::check<T>(0)){};
Explanation time~
Your original code works† because a default template argument's point of instantiation is the point of instantiation of its function template, meaning, in your case, in main
, so it can't be substituted earlier than that.
§14.6.4.1 [temp.point] p2
If a function template [...] is called in a way which uses the definition of a default argument of that function template [...], the point of instantiation of the default argument is the point of instantiation of the function template [...].
After that, it's just usual SFINAE rules.
† Atleast I think so, it's not entirely clear in the standard.
这篇关于使用SFINAE检测constexpr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!