helios, yes that would have been great. Unfortunately it seems like compilers treat functions as optimization boundaries. They do a lot of optimizations inside functions but not so much between functions (unless the function is inlined).
I have been thinking a little about this "problem" before and the "solution" that I came up with was to wrap the value type of the in parameters and use templates to try and decide the best type to use.
This is what a function would look like.
1 2 3 4
|
void foo(in<int> x)
{
std::cout << x << std::endl;
}
|
The way it works is that I have a function that tells me if a type is efficient to copy or not. The criteria that I used was that the type must be small and be trivially copyable.
1 2 3 4 5 6
|
template<typename T>
constexpr bool is_efficient_to_copy()
{
return std::is_trivially_copyable_v<T> &&
sizeof(T) <= 2 * sizeof(std::size_t);
}
|
Then I just define a template struct to hold the optimal in-parameter type for each type. The default is pass-by-reference. Types that are considered more "efficient to copy" are passed by value.
1 2 3 4 5 6 7 8 9 10 11
|
template<typename T, typename Enable = void>
struct In
{
using type = const T&;
};
template<typename T>
struct In<T, std::enable_if_t<is_efficient_to_copy<T>()>>
{
using type = const T;
};
|
Note that I used const even for pass-by-value because I didn't want code to break if, for some reason, a type changes from pass-by-value to pass-by-reference.
In order to make it less verbose and easier to use I make use of an alias template.
1 2
|
template<typename T>
using in = typename In<T>::type;
|
This seems to work fine but I haven't done any benchmarks yet to see if it's worth it. I'm not at all sure about the size limit in is_efficient_to_copy() but at least it is easy to change. When a program has been written this way it could be benchmarked with different values to see what performs best.
It is also quite easy to specialize for individual types. Maybe this could be automated using a tool that runs a benchmark for each type T that it finds as "in<T>" in the code and then writes all the optimized specializations to a code file that is included in the header file.
For consistency my plan was to have similar syntax for
out parameters and
in-out parameters as well, and perhaps also something for detecting the optimal type when you want to move from the parameter. This would also work as documentation of the purpose of the parameters. Maybe I try to use something like this for a small toy project in the future, not that I do think it will make a huge noticeable difference, but it could maybe be fun and I might learn something from it. In the meantime I'm just hoping compilers get better at optimizing these things.