假设我写了:
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>(); }
当我编译这个时,我得到一个关于调用歧义的错误(如果我用 float
替换 short
则没有错误)。我应该如何修复此代码,以便获得整数类型的较高版本和较低版本?
如果您的建议适用于 foo()
的多个专用版本以及通用版本,则可加分。
最佳答案
我喜欢 Xeo's approach对于这个问题。让我们做一些带有后备的标签调度。创建一个从自身向下继承的选择器结构:
template <int I>
struct choice : choice<I + 1> { };
template <> struct choice<10> { }; // just stop somewhere
所以 choice<x>
可转换为 choice<y>
对于 x < y
,这意味着 choice<0>
是最好的选择。现在,您需要最后一个案例:
struct otherwise{ otherwise(...) { } };
有了这个机制,我们可以用一个额外的参数来转发我们的主函数模板:
template <class T> void foo() { foo_impl<T>(choice<0>{}); }
然后让你的 top 选择变得完整,你最坏的选择......任何东西:
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;
}
这使得在中间添加更多选项变得非常容易。只需为 choice<1>
添加重载即可或 choice<2>
管他呢。也不需要不相交的条件。 choice<x>
的优先重载解决方案照顾它。
如果你另外传入 T
就更好了作为一个论点,因为重载比专门化要好得多:
template <class T> struct tag {};
template <class T> void foo() { foo_impl(tag<T>{}, choice<0>{}); }
然后你就可以疯狂了:
// 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 );
关于c++ - 解决此模板分辨率歧义的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36221449/