繁体   English   中英

可变参数模板递归编译时 function

[英]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 ) ;
};

但我不明白为什么递归版本不起作用(这类似于https://stackoverflow.com/users/1365260/example的版本如何编写可变参数模板递归 function?

// 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;
}

程序的output为:

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-if

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<<起作用。 如果需要,您需要将 function 命名为operator<< ,而不是toOstream2()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM