【发布时间】:2021-10-06 18:24:40
【问题描述】:
这个问题是出于疯狂的好奇心,而不是实际问题。 考虑the following code:
template<typename...>
struct type_list {};
template<typename, typename = void>
struct test_class;
template<typename... T>
struct test_class<type_list<T...>> {
static constexpr auto value = false;
};
template<typename T>
struct test_class<type_list<T>, std::enable_if_t<std::is_same_v<T, int>>> {
static constexpr auto value = true;
};
int main() {
static_assert(!test_class<type_list<double, char>>::value);
static_assert(test_class<type_list<int>>::value);
}
这失败并出现错误:
'test_class
' 的模糊偏特化
如果我将第二个专业化更改为从功能角度来看不起作用的东西,the error would go away:
template<typename T>
struct test_class<type_list<T>> {
static constexpr auto value = true;
};
同样,如果我使用别名模板void_t,everything works as expected:
template<typename T>
struct test_class<type_list<T>, std::void_t<std::enable_if_t<std::is_same_v<T, int>>>> {
static constexpr auto value = true;
};
除了组合void_t 和enable_if_t 的丑陋之外,当存在与int 不同的单一类型时,这也可以完成工作,即对于static_assert(!test_class<type_list<char>>::value)(它不会在第二种情况,原因很明显)。
我明白为什么第三种情况works-ish,因为当满足enable_if_t 的条件并且@ 987654336@ 比 type_list<T...> 更专业(对吗?)。
但是,我对以下内容也有同样的期望:
template<typename T>
struct test_class<type_list<T>, std::enable_if_t<std::is_same_v<T, int>>> {
static constexpr auto value = true;
};
在一天结束时,std::enable_if_t<std::is_same_v<T, int>> 不知何故是 void 当条件满足时(好吧,从技术上讲它是typename blabla::type,被授予但不是::type 仍然@ 987654343@?),因此我不明白为什么它会导致模棱两可的电话。我很确定我在这里遗漏了一些明显的东西,我现在很想理解它。
如果您能为此指出 standardese 并告诉我是否存在比最终组合 void_t 和 enable_if_t 更好的解决方案,我会很高兴。
【问题讨论】:
-
仅供参考(因为您的链接是用 C++20 编译的)它适用于约束 godbolt.org/z/PWrEMqKEv
-
哦,我的错,对不起。首先,感谢您的反馈,因为了解 C++20 总是好的。但是,它是错误地用 C++20 编译的。 :)§虽然,是的,很高兴知道我将来能够摆脱丑陋!特别是如果我今天找不到更好的东西。
-
我不认为
type_list<T>比type_list<T...>更专业。它们在 1 个参数上都可以很好地匹配。我觉得这个问题有点落后。我更惊讶的是,当您使用void_t时它确实有效。我原以为您需要禁用第一个专业化才能完全避免混淆(例如here)。 -
嗯,我认为确实如此。非正式地,可变参数形式比单一类型形式满足更多的情况。除此之外,我已经使用这个技巧无数次了,现在发现 它不起作用 会令人震惊。所以,让我们在这里停止讨论! :D 无论如何,为了简洁起见,我使用了可变参数模板,但问题可以很容易地映射到不使用它的示例。所以,抛开玩笑,请不要专注于它。
标签: c++ templates c++17 sfinae template-specialization