首页 > 解决方案 > 为什么专业化论证必须无效?

问题描述

所以这个传奇中的另一个问题。Guillaume Racicot已经足够好,可以为我提供另一种解决方法,所以这是我提出这个问题的代码:

struct vec
{
    double x;
    double y;
    double z;
};

namespace details
{
template <typename T>
using subscript_function = double(*)(const T&);

template <typename T>
constexpr double X(const T& param) { return param.x; }

template <typename T>
constexpr double Y(const T& param) { return param.y; }

template <typename T>
constexpr double Z(const T& param) { return param.z; }
}

template <typename T, typename = void>
constexpr details::subscript_function<T> my_temp[] = { &details::X<T>, &details::Y<T> };

template <typename T>
constexpr details::subscript_function<T> my_temp<T, enable_if_t<is_floating_point_v<decltype(details::X(T()))>, T>>[] = { &details::X<T>, &details::Y<T>, &details::Z<T> };


int main() {
    vec foo = { 1.0, 2.0, 3.0 };

    for(const auto i : my_temp<decltype(foo)>) {
        cout << (*i)(foo) << endl;
    }
}

当我返回. void例如,在上面的代码中,enable_if_t<is_floating_point_v<decltype(details::X(T()))>, T>防止特化,而简单地删除最后一个参数并允许enable_if返回void允许特化。

我认为这表明我对这里真正发生的事情的误解。为什么必须始终使用专门的类型才能void使其正常工作?

Live Example

标签: c++templatestemplate-specializationenable-iftemplate-variables

解决方案


不确定你不明白的地方,但是......

如果你写

template <typename T, typename = void>
constexpr details::subscript_function<T> my_temp[] = { &details::X<T>, &details::Y<T> };

template <typename T>
constexpr details::subscript_function<T> my_temp<T, enable_if_t<is_floating_point_v<decltype(details::X(T()))>, T>>[] = { &details::X<T>, &details::Y<T>, &details::Z<T> };

您有一个第一个主要的模板变量,其中包含两个模板:一个类型和一个具有默认值 ( void) 的类型。

第二个模板变量在 is 时std::enable_if_t启用void

写作时发生了什么

for(const auto i : my_temp<decltype(foo)>) 

?

编译器:

1)找到my_temp<decltype(foo)>具有单个模板参数的

2) 寻找匹配的my_temp模板变量

3)只找到一个my_temp有两个模板参数但第二个有一个默认值,所以

4)决定my_temp<decltype(foo)>只能my_temp<decltype(foo), void>(或者my_temp<vec, void>,如果你愿意)

5)看到主要my_temp匹配

6)看到my_temp专业化不匹配,因为

enable_if_t<is_floating_point_v<decltype(details::X(T()))>, T>

T(即vec),因此只能匹配与my_temp<vec, vec>不同的my_temp<vec, void>

7) 选择唯一可用的模板变量:主变量。

如果您希望通过以下方式启用专业化

enable_if_t<is_floating_point_v<decltype(details::X(T()))>, T>

你应该使用T

// ..............................V   T! not void
template <typename T, typename = T>
constexpr details::subscript_function<T> my_temp[] = { &details::X<T>, &details::Y<T> };

作为主模板变量中第二个模板类型的默认值。

题外话建议:最好std::declvalstd::is_floating_point_v测试内使用;我建议

std::enable_if_t<std::is_floating_point_v<decltype(details::X(std::declval<T>()))>>

推荐阅读