#Determining, at compile time, to create a copy or a get a reference (c++17)

35 messages · Page 1 of 1 (latest)

fair heart
#

Does this cause fu to have different types depending on the value of b? ie if b then fu is a copy of foo, otherwise it is a reference to foo.

template <bool b, class Foo>
constexpr decltype(auto) bar(Foo && foo) {
  if constexpr (b) {
    return std::decay_t<Foo>{foo};
  } else {
    return (foo);
  }
}

template <bool b>
auto baz(Foo& foo) {
  decltype(auto) fu = bar<b>(foo);
  ...
}

If not, is it even possible? And how would it be done?

willow topazBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question run !howto ask.

fair heart
#

Determining, at compile time, to create a copy or a get a reference (c++17)

celest urchin
#

Besides some weirdnesses I don't quite understand this should work as is.

#

You'll probably get into problems because partial template argument deduction is somehow not allowed, but bar<true> and bar<false> are different functions and can therefore have different return types.

acoustic solar
tight ingot
#
template<bool b, class T>
struct Ret;

template<class T>
struct Ret<true, T> {
  using type = T&&;
};

template<class T>
struct Ret<false, T>{
  using type = T;
};
#

I think you'll run into issues with Foo && being a universal reference though unless you do a bunch of remove_reference stuff, etc

acoustic solar
#

as to the original question, as already stated by @Toeger, the return types are in fact different for different values of b

tight ingot
#
template <bool b, class Foo>
constexpr Ret<b>::type bar(Foo && foo)
#

if it can't be inferred this will still get the return type correct

acoustic solar
#

both options don't seem to preserve the original types

#

i guess it's more like std::conditional_t<b, std::decay_t<Foo>, Foo &>

tight ingot
#

and yeah thats what I meant by needing to mess around with getting the actual type you want to do this to

#

rather than using Foo because that will have various qualifiers hidden within it

lethal hare
fair heart
#

tbh its not for me. one of my coworkers came to me with a less than correct implementation, so im just helping him out.

#

as i understand it, the boolean determines if we're being threadsafe, ie if we're in multithreaded mode. and if we are then copy the datastructure because its faster than locking etc and we dont need to sync until later. otherwise just grab a reference because theres no risk of race

lethal hare
#

this doesn't really sound like hot code anyways

#

btw in C++23, you can avoid std::decay_t and return auto(foo)

fair heart
#

yea i know. is why i added 17 to the title

lethal hare
#

or simply return Foo(foo) since the intention is to always copy anyways

fair heart
#

hmm... true

lethal hare
#

and if it was possible to move instead of copying, then this problem wouldn't exist in the first place

#

since moving is fast enough to where you don't need to conditionally reference instead of moving

fair heart
#

i think moving is something we're avoiding. as we want to keep the original alive

lethal hare
#

locking is cheap if you don't run into conflicts anyways

#

maybe std::shared_mutex would be good here

#

if you infrequently write and have frequent shared reads, then there are pretty much no costs over single-threaded code

fair heart
#

actually i think that this arose because of (or at least after) a bug caused by std::shared_mutex on m1.