如何' std::initializer_list '值通过编译器?(或者:我怎样才能避免一个普遍的超载?)

How are `std::initializer_list` values passed by the compiler? (Or: how can I get around a universal overload with one?)

本文关键字:能避免 一个 超载 list initializer std 或者 如何 编译器      更新时间:2023-10-16

继续我的故事,我已经意识到我可以重载我的访问函数,使用单个std::initializer_list参数代替:

class array_md
{
    //...
    my_type &        operator []( size_type i )
    { /* Lots of code */ }
    my_type const &  operator []( size_type i ) const
    { /* same Lots of code, with "const" sprinkled in */ }
    my_type &        operator []( std::initializer_list<size_type> i )
    { /* Lots of different code */ }
    my_type const &  operator []( std::initializer_list<size_type> i ) const
    { /* same Lots of different code, with "const" sprinkled in */ }
    //...
};

对于我的at版本我现在有:

class array_md
{
    //...
    template < typename ...Index >
    complicated &        at( Index &&...i )  // (1)
    { /* Lots of code */ }
    template < typename ...Index >
    complicated const &  at( Index &&...i ) const  // (2)
    { /* same Lots of code, with "const" sprinkled in */ }
    my_type &            at( std::initializer_list<size_type> i )  // (3)
    { /* Lots of different code */ }
    my_type const &      at( std::initializer_list<size_type> i ) const  // (4)
    { /* same Lots of different code, with "const" sprinkled in */ }
    //...
};

(由于不能根据初始化器列表中的条目数量更改类型,因为它是运行时的,所以我修复了返回类型,如果条目数量错误则抛出。)新的重载代码很长,我必须为mutableconst版本重复它,所以我想知道如何保存代码。我试着修改const_cast:

class array_md
{
    //...
    my_type &        operator []( size_type i );
    my_type const &  operator []( size_type i ) const;
    my_type &        operator []( std::initializer_list<size_type> i )
    {
        return const_cast<my_type &>( const_cast<array_md const
         *>(this)->operator [](i) );
    }
    my_type const &  operator []( std::initializer_list<size_type> i ) const;
    //...
};

这里第三个版本调用第四个版本,使用const_cast来避免编译器的投诉。(侵入是可以的,因为我剥离const从我打了它开始。不要反转依赖关系;你最终可能会在一个真正的const对象上调用mutable成员函数!)我试图为at做同样的事情,用标记为(4)的重载实现标记为(3)的重载。然而,由于at有三个替代方案,我得到了与(2)相关的错误。是否有一些我如何传递std::initializer_list到内部at调用(按值),这不会导致与通用过载相比的精确匹配?我是通用方法冲突的老朋友。

TL;DR:示例代码显示std::initializer_list对象在函数参数列表中按值获取。这是编译器在传递它们时的首选项吗?还是通过引用?如果您需要精确匹配(以克服通用重载),这一点很重要。

消歧强制转换:

int     f( int );
double  f( double );
template < typename Func, typename ...Args >
void  do_it( Func &&f, Args &&...a );
//...
int  main( int, char *[] )
{
    do_it( (double(*)(double))&f, 5.4 );
    return 0;
}

main中的代码强制使用f的第二个版本。我以为这个能力是C-cast独有的,但它在static_cast下。所以我得到了这样的东西:

class array_md
{
    //...
    template < typename ...Index >
    complicated &        at( Index &&...i );  // (1)
    template < typename ...Index >
    complicated const &  at( Index &&...i ) const;  // (2)
    my_type &            at( std::initializer_list<size_type> i )  // (3)
    {
        return const_cast<my_type &>(
          (
            const_cast<array_md const *>( this )
            ->*
            static_cast<
              my_type const &
              (array_md::*)
              ( std::initializer_list<size_type> ) const
            >( &array_md::at )
          )( i )
        );
    }
    my_type const &      at( std::initializer_list<size_type> i ) const;  // (4)
    //...
};

(我得到了我的灵感,通过回答别人的帖子需要区分函数模板重载。)这需要进行几次尝试,特别是没有创建中间对象。