为何主模板优先于特化模板被选中?C++17模板匹配问题
问题
以下是严格符合C++17标准的程序吗?其返回值是否不应由实现定义?若是,正确返回值是什么?
template <char... Chars> struct foo { inline static constexpr bool primary = true; }; template <bool Bool, char... Chars> struct foo<Bool, Chars...> { inline static constexpr bool primary = false; }; // 5 int main() { return foo<true>::primary; // gcc: 1, clang & icx: 0 }
我原本预期所有编译器都会选择特化模板,因为foo<true>无需将布尔值true转换为char即可匹配特化模板,且特化模板比主模板更具约束性(要求至少一个参数)。但在基于gcc 7.3的工具链中,上述代码无法编译,报错信息如下:
<source>:5:8: error: template argument '(char)Bool' involves template parameter(s) struct foo<Bool, Chars...> { inline static constexpr bool primary = false; }; ^~~~~~~~~~~~~~~~~~~
因此我使用gcc(trunk)测试,意外发现虽然代码可编译,但gcc选择了主模板。
若将true改为'a',clang和icx也会像gcc一样选择主模板,符合我的预期:
template <char... Chars> struct foo { inline static constexpr bool primary = true; }; template <bool Bool, char... Chars> struct foo<Bool, Chars...> { inline static constexpr bool primary = false; }; int main() { return foo<'a'>::primary; // gcc: 1, clang & icx: 1 }
我尝试在C++17最终草案的[temp]章节中寻找答案,但未能理清逻辑。
解决方案
我实现了一个detail::foo_impl作为基类:
#include <type_traits> namespace detail { template <bool Bool, char... Chars> struct foo_impl { static constexpr bool value = Bool; }; } // namespace detail
主模板改为如下形式:
// The primary template which selects a value for the bool using // some disjunction or conjunction. Here simplified to a fold: template <char... Chars> struct foo : detail::foo_impl<(... || (Chars == ' ')), Chars...> {};
特化模板则更直观:
// Specializations for `false` and `true`: template <char... Chars> struct foo<false, Chars...> : detail::foo_impl<false, Chars...> {}; template <char... Chars> struct foo<true, Chars...> : detail::foo_impl<true, Chars...> {};
现在所有编译器(包括gcc7.3)的表现一致,且符合我的初始需求。
内容的提问来源于stack exchange,提问作者Ted Lyngmo
相关产品推荐
相关产品推荐

