c++ - 解决此模板分辨率歧义的正确方法是什么?

标签 c++ c++11 c++14 sfinae enable-if

假设我写了:

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/

相关文章:

c++ - 使用 D3DUSAGE_DYNAMIcflags时,DirectX 9 顶点缓冲区使程序崩溃

c++ - D3DXERR_INVALIDDATA 发生

C++11:lambda malloc 每次声明时都会占用空间吗?

c++ - 调用函数的歧义。隐式转换?

C++14 警告 : too many template headers for variable (should be 0)

c++ - GCC constexpr constexpr 函数中的 lambdas 和编译时的评估

c++ - 使用 C++ 和 Linux 的高分辨率计时器?

c++ - 这个未定义的行为或实现是否已定义?

c++ - c32rtomb 转换成什么编码?

c++ - 包含原始类型的结构容器,零初始化?