this saga 中的另一个问题. Guillaume Racicot已经足够好了,可以为我提供 yet another workaround所以这是我提出这个问题的代码:
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
这行得通吗?
最佳答案
不确定你不明白的是什么,但是......
如果你写
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
)。
当 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::declval
在std::is_floating_point_v
里面测试;我建议
std::enable_if_t<std::is_floating_point_v<decltype(details::X(std::declval<T>()))>>
关于c++ - 为什么特化论证必须无效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56667847/