我正在升级一些 C++ 代码以利用 C++11 中的新功能.我有一个 trait 类,其中有几个函数返回基本类型,这些函数在大多数情况下(但并非总是)返回一个常量表达式.我想根据函数是否为 constexpr
来做不同的事情.我想出了以下方法:
template结构测试{模板静态 std::true_type do_call(int){ return std::true_type();}静态 std::false_type do_call(...){ 返回 std::false_type();}static bool call(){ return do_call(0);}};结构特征{静态 int f(){ 返回 15;}};结构特征{静态 constexpr int f(){ 返回 20;}};int main(){std::cout <<常规:" <<测试<特质>::call()<<std::endl;std::cout <<constexpr:" <<测试<ctrait>::call()<<std::endl;}
额外的 int
/...
参数在那里,如果 SFINAE 之后两个函数都可用,第一个被选择重载解析.
使用 Clang 3.2 编译和运行它显示:
常规:0常量表达式:1
所以这似乎有效,但我想知道代码是否是合法的 C++11.特别是根据我的理解,SFINAE 的规则已经改变.
注意: 我在这里提出了一个问题,关于 OP 代码是否实际有效.我在下面重写的示例在任何情况下都可以使用.
<小时><块引用>
但我想知道代码是否合法 C++11
确实如此,虽然默认模板参数可能被认为有点不寻常.我个人更喜欢以下样式,这类似于您(阅读:我)编写特征以检查函数是否存在,仅使用非类型模板参数并省略 decltype
:
#include 命名空间细节{模板结构 sfinae_true : std::true_type{};模板sfinae_true<(T::f(), 0)>检查(整数);模板<类>std::false_type 检查(...);}//细节::模板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)){};
Live example.
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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!