ein*_*ica 24 c++ sfinae enable-if c++11 c++14
假设我写了:
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
void foo() { std::cout << "T is integral." << std::endl; }
template <typename T>
void foo() { std::cout << "Any T." << std::endl; }
int main() { foo<short>(); }
Run Code Online (Sandbox Code Playgroud)
当我编译它时,我得到一个关于调用歧义的错误(如果我替换short,则没有错误float).我应该如何修复此代码,以便获得整数类型的较高版本和较低版本?
如果您的建议扩展到foo()除了一般版本之外的多个专业版本的情况,则奖励积分.
Bar*_*rry 14
我喜欢Xeo解决这个问题的方法.让我们做一些带有后备的标签调度.创建一个从其自身继承的选择器结构:
template <int I>
struct choice : choice<I + 1> { };
template <> struct choice<10> { }; // just stop somewhere
Run Code Online (Sandbox Code Playgroud)
所以choice<x>可以转换为choice<y>for x < y,这意味着这choice<0>是最好的选择.现在,您需要最后一个案例:
struct otherwise{ otherwise(...) { } };
Run Code Online (Sandbox Code Playgroud)
有了这个机器,我们可以使用额外的参数转发我们的主函数模板:
template <class T> void foo() { foo_impl<T>(choice<0>{}); }
Run Code Online (Sandbox Code Playgroud)
然后让你的顶部选择积分和您的最坏情况下的选项...什么:
template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
void foo_impl(choice<0> ) {
std::cout << "T is integral." << std::endl;
}
template <typename T>
void foo_impl(otherwise ) {
std::cout << "Any T." << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这使得在中间添加更多选项变得非常容易.只需为choice<1>或等添加重载choice<2>.也不需要不相交的条件.优先重载解决方案choice<x>可以解决这个问题.
如果你另外传入T一个参数更好,因为重载比专门化更好:
template <class T> struct tag {};
template <class T> void foo() { foo_impl(tag<T>{}, choice<0>{}); }
Run Code Online (Sandbox Code Playgroud)
然后你可以疯狂:
// special 1st choice for just int
void foo_impl(tag<int>, choice<0> );
// backup 1st choice for any integral
template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
void foo_impl(tag<T>, choice<0> );
// 2nd option for floats
template <class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
void foo_impl(tag<T>, choice<1> );
// 3rd option for some other type trait
template <class T, class = std::enable_if_t<whatever<T>::value>>
void foo_impl(tag<T>, choice<2> );
// fallback
template <class T>
void foo_impl(tag<T>, otherwise );
Run Code Online (Sandbox Code Playgroud)
ser*_*gej 10
使用标签分派的另一个选项(C++ 11):
#include <iostream>
void foo_impl(std::false_type) {
std::cout << "Any T." << std::endl;
}
void foo_impl(std::true_type) {
std::cout << "T is integral." << std::endl;
}
template <typename T>
void foo() {
foo_impl(std::is_integral<typename std::remove_reference<T>::type>());
//foo_impl(std::is_integral<typename std::remove_reference_t<T>>()); // C++14
}
int main() {
foo<short>(); // --> T is integral.
foo<short&>(); // --> T is integral.
foo<float>(); // --> Any T.
}
Run Code Online (Sandbox Code Playgroud)
借用Scott Meyers Effective Modern C++第 27项.
单程:
template <typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
void foo() { std::cout << "T is integral." << std::endl; }
template <typename T, typename std::enable_if_t<not std::is_integral<T>::value>* = nullptr>
void foo() { std::cout << "Any T." << std::endl; }
Run Code Online (Sandbox Code Playgroud)
另一种方法是推迟模板函数对象:
template<class T, typename = void>
struct foo_impl
{
void operator()() const {
std::cout << "Any T." << std::endl;
}
};
template<class T>
struct foo_impl<T, std::enable_if_t<std::is_integral<T>::value>>
{
void operator()() const {
std::cout << "T is integral." << std::endl;
}
};
template<class T>
void foo() {
return foo_impl<T>()();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1243 次 |
| 最近记录: |