You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何主模板优先于特化模板被选中?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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 13:33:27