C++:解析模板类构造函数模板参数中int&...的用法
模板类中
int&...作为显式参数屏障的作用验证 问题场景
我在一段源码中发现了如下使用int&...的模板类A示例(第1行):
template <typename Char> struct A { public: template <int&..., size_t N> // Line 1 // template <size_t N> // Line 2 constexpr A(const Char (&arr)[N]) noexcept : ptr_(arr), len_(std::char_traits<Char>::length(arr)) {} const Char* c_str() const noexcept { return ptr_; } private: const Char* ptr_ = nullptr; size_t len_ = 0; }; using AChar = A<char>; template <typename Char, typename Traits> std::basic_ostream<Char, Traits>& operator<<( std::basic_ostream<Char, Traits>& os, A<Char> view) { return os << view.c_str(); }
无论使用第1行还是第2行的模板参数定义,以下测试代码均可正常编译:
int main() { constexpr auto a = A{"hello"}; static constexpr char kArr[] = "hell"; constexpr auto a1 = A{kArr}; constexpr A a2{"hello"}; constexpr A a3{kArr}; std::cout << a << '\n'; std::cout << a1 << '\n'; std::cout << a2 << '\n'; std::cout << a3 << '\n'; }
相关内容提到了ExplicitArgumentBarrier(显式参数屏障),针对模板函数的示例如下:
template <int&... ExplicitArgumentBarrier, typename T> void AcceptSomeReference(const T&) {}
这种写法会导致如下调用编译失败:
AcceptSomeReference<char>('c');
请问对于类A,如何进行显式模板参数指定的尝试才会被int&...阻止?
解答
核心原理
int&...作为模板参数的作用是阻止用户显式指定后续的模板参数:因为引用类型的模板参数无法被常规显式推导或指定(除非提供全局左值int变量的引用,但这并非正常使用场景,也违背设计意图)。
针对类A的验证尝试
类A的构造函数是模板函数,模板参数顺序为int&...在前、size_t N在后。如果尝试显式指定N的取值,就会触发这个屏障的阻止作用:
比如尝试以下写法:
// 尝试显式指定构造函数的模板参数N constexpr A<char> a4 = A<char>::template A<5>("hello");
以上代码会编译失败,原因有两点:
- 当显式指定
5作为模板参数时,编译器会优先匹配第一个模板参数int&...,但5是右值,无法绑定到int&类型的引用参数; - C++不允许跳过前面的模板参数直接指定后面的——若要指定
N,必须先为int&...提供合法实参,但实际上你无法提供符合要求的实参(需要全局左值int的引用,这不是正常使用场景)。
而如果是没有int&...的版本(第2行),上面的显式指定写法是合法的:
// 无int&...时,该写法可正常编译 constexpr A<char> a5 = A<char>::template A<5>("hello");
这就体现了int&...作为显式参数屏障的作用:强制用户让编译器隐式推导N,避免用户错误指定不符合数组实际长度的N值。
内容的提问来源于stack exchange,提问作者cbhattac
相关产品推荐
相关产品推荐

