Continuing my saga, I've realized that I can make overloads of my access functions, using a single std::initializer_list
parameter instead:
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 */ }
//...
};
For my version of at
I now have:
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 */ }
//...
};
(Since I can't change the type depending on the amount of entries in an initializer-list, because it's run-time, I fix the return type and throw if the number of entries is wrong.) The code for the new overloads is long, and I have to repeat it for the mutable
and const
versions, so I'm wondering how to save code. I tried to mess with 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;
//...
};
Here the third version calls the fourth, using const_cast
to get around compiler complaints. (The trespass is OK since I'm stripping const
from something I slapped it on to begin with. Don't reverse the dependencies; you may end up calling a mutable
member function on a truly const
object!) I tried to do the same thing for at
, implementing the overload marked (3) with the one marked (4). However, since there are three alternates for at
, I got errors related to (2) getting selected instead! Is there something to how I'm passing the std::initializer_list
to the inner at
call (by value) that doesn't cause an exact match compared to a universal overload? I'm old friends with universal method conflicts.
TL;DR: Example code shows std::initializer_list
objects being taken by value in function parameter lists. Is that the compiler's first preference in passing them? Or is it by reference instead? This is important if you need an exact match (to defeat a universal overload).