4

继续我的传奇,我意识到我可以使用单个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从一开始就打它的东西剥离。不要颠倒依赖关系;你最终可能会mutable在一个真正的const对象上调用一个成员函数!)我试图做同样的事情at,用标记为 (4) 的过载实现标记为 (3) 的过载。但是,由于 有 3 个替代项at,因此我得到了与 (2) 被选中相关的错误!与通用重载相比,我如何将 传递std::initializer_list给内部at调用(按值)不会导致完全匹配?我是普遍方法冲突的老朋友。

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

4

1 回答 1

0

消歧义:

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

(我的灵感来自于回答别人关于需要区分函数模板重载的帖子。)尝试了几次,尤其是在不必创建中间对象的情况下。

于 2013-04-30T01:39:54.490 回答