可变模板递归编译时间函数
variadic template recursive compiletime function
在可变模板中存在一些情况,我不明白它们为什么不起作用。例如,我有一个存储几个字符的模板类型:
template<char...chars> struct Test{
};
// If I try to print it with parameter packs everything okay.
template<char...chars>
constexpr std::ostream& toOstream( std::ostream & os , Test <chars...> ) {
return ( os << ... << chars ) ;
};
但我不明白为什么递归版本不起作用(这是simmilarhttps://stackoverflow.com/users/1365260/example的版本在如何编写可变模板递归函数?(:
// Case A
template<char c=0, char...chars>
constexpr std::ostream& toOstream2( std::ostream & os , Test <c,chars...> ) {
return sizeof...(chars) == 0 ? ( os << c ) :
toOstream2( os << c, Test<chars...>() ) ;
};
// Case B: Nor I understand why can't I use it inside another class:
template< class Base >
struct Deriv{
static constexpr std::ostream& toOstream( std::ostream & os ) {
return ( os << Base() );
};
};
// main program:
int main(void){
toOstream( cout, Test<'k','a','b'>() ) << endl;
//toOstream2( cout, Test<'k','a','b'>() ) << endl; // this gives error. Case A
//Deriv< Test<'k','a','b'> >().toOstream( cout ) << endl; // this gives error. Case B
return 1;
}
程序的输出为:
kab
如果我取消对案例A的注释,则错误为:
xxxxxxxxxxx: In instantiation of ‘constexpr std::ostream& toOstream2(std::ostream&, Test<c, chars ...>) [with char c = 'b'; char ...chars = {}; std::ostream = std::basic_ostream<char>]’:
xxxxxxxxxxx: recursively required from ‘constexpr std::ostream& toOstream2(std::ostream&, Test<c, chars ...>) [with char c = 'a'; char ...chars = {'b'}; std::ostream = std::basic_ostream<char>]’
...etc
xxxxxxxxxxxxxxxx: note: candidate expects 2 arguments, 0 provided
| toOstream2( os << c, Test<chars...>() ) ;
| ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
对于案例B:
error: no match for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘Test<'k', 'a', 'b'>’)
60 | return ( os << Base() );
| ~~~~~^~~~~~~~~~~
我正在使用g++10.2.1 20210110
有什么提示吗?
编辑:看了答案后,我想知道为什么这个编译没有问题,而我的案例A没有
template<int First=0, int... Rest>
constexpr int fauo()
{
return sizeof...(Rest)==0 ? First : First + fauo<Rest...>();
}
#include<iostream>
int main(void){
std::cout << fauo<0,9>() << std::endl;
return 0;
}
对于不适用于类的函数,有什么特别的东西吗?
要使其工作,您需要在编译时解析sizeof...(char)
。如果:,则可以使用constexpr
template <char c, char... chars>
constexpr std::ostream& toOstream2(std::ostream& os, Test<c, chars...>) {
if constexpr (sizeof...(chars) == 0) return os << c;
else return toOstream2(os << c, Test<chars...>());
};
或者C++17之前的版本,使用重载:
template <char c>
constexpr std::ostream& toOstream2(std::ostream& os, Test<c>) {
return os << c;
};
template <char c, char... chars>
constexpr std::ostream& toOstream2(std::ostream& os, Test<c, chars...>) {
return toOstream2(os << c, Test<chars...>());
};
对于情况B,您需要使用Base
实例调用toOstream2
,而不是尝试执行os << Base()
,因为您尚未为Base
定义operator<<
。
template <class Base>
struct Deriv {
static constexpr std::ostream& toOstream(std::ostream& os) {
return toOstream2(os, Base{});
};
};
添加operator<<
过载后,您的案例B可能如下所示:
#include <iostream>
template <char... chars> struct Test {};
template <char c, char... chars>
std::ostream& operator<<(std::ostream& os, Test<c, chars...>) {
if constexpr (sizeof...(chars) == 0) return os << c;
else return os << c << Test<chars...>{};
};
template <class Base>
struct Deriv {
friend std::ostream& operator<<(std::ostream& os, const Deriv<Base>&) {
return os << Base{};
};
};
int main() {
std::cout << Test<'k','a','b'>() << 'n'; // prints "kab"
std::cout << Deriv<Test<'k','a','b'>>() << 'n'; // prints "kab"
}
第一个(案例A(不起作用,因为您希望模板至少有一个参数。如果您指定了默认参数,情况也是如此。要使其工作,只需在toOstream2()
定义为:之前允许一个0字符重载
constexpr std::ostream& toOstream2( std::ostream & os , Test <> ) { return os; }
第二个(案例B(不起作用,因为您还没有调用toOstream2()
,但希望operator<<
起作用。如果需要,您需要将函数命名为operator<<
,而不是toOstream2()
。
相关文章:
- 使用简单类型列表实现的指数编译时间.为什么
- 在已经使用Git的情况下减少编译时间
- C++常量数组的编译时间较长
- 编译时间文本到数字转换 (atoi)
- 在C++中执行 N 阶乘编译时间的 3 种不同/相同方法
- DLLexport 类模板实例(专用化),减少了仅标头模板库的编译时间
- 替换枚举以最大化编译时间检查的最佳方法
- 不同C++功能的编译时间
- 在预编译标头中实例化模板会缩短编译时间吗?
- 使用 SCons 提取每个编译单元的编译时间
- 将 lambda 函数转换为另一个编译单元中的普通函数会缩短编译时间吗?
- std :: Invoke_result_t编译时间语法错误
- 模板;constexpr;编译时间
- 如何实现声明功能-C 11,编译时间
- 如何减少编译时间:在包含未触及的头文件的情况下
- C++编译时间类型确定
- 特征:返回对具有编译时间尺寸检查的矩阵块的引用
- 在编译时间定义多个派生类
- 在编译时间创建查找表
- C 函数在编译时间返回类型