3

Is there any way to create a type A such that:

Given:

A f(...);

Then:

Both auto&& a = f(...); and const auto& a = f(...); give a compile errors?

The reason for this is that in this case, A is an expression template which contains references to temporaries (that are provided as arguments to f), so I don't want the lifetime of this object extended beyond the current expression.

Note I can prevent auto a = f(...); from being an issue just by making As copy constructor private, and making f(...) a friend of A if required.

Example of code (ideone link):

#include <iostream>
#include <array>

template <class T, std::size_t N>
class AddMathVectors;

template <class T, std::size_t N>
class MathVector
{
public:
  MathVector() {}
  MathVector(const MathVector& x) 
  { 
    std::cout << "Copying" << std::endl;
    for (std::size_t i = 0; i != N; ++i)
    {
      data[i] = x.data[i];
    }
  }
  T& operator[](std::size_t i) { return data[i]; }
  const T& operator[](std::size_t i) const { return data[i]; }
private:
  std::array<T, N> data;
};

template <class T, std::size_t N>
class AddMathVectors
{
public:
  AddMathVectors(const MathVector<T,N>& v1, const MathVector<T,N>& v2) : v1(v1), v2(v2) {}
  operator MathVector<T,N>()
  {
    MathVector<T, N> result;
    for (std::size_t i = 0; i != N; ++i)
    {
      result[i] = v1[i];
      result[i] += v2[i];
    }
    return result;
  }
private:
  const MathVector<T,N>& v1;
  const MathVector<T,N>& v2;
};

template <class T, std::size_t N>
AddMathVectors<T,N> operator+(const MathVector<T,N>& v1, const MathVector<T,N>& v2)
{
  return AddMathVectors<T,N>(v1, v2);
}

template <class T, std::size_t N>
MathVector<T, N> ints()
{
  MathVector<T, N> result;
  for (std::size_t i = 0; i != N; ++i)
  {
    result[i] = i;
  }
  return result;
}

template <class T, std::size_t N>
MathVector<T, N> squares()
{
  MathVector<T, N> result;
  for (std::size_t i = 0; i != N; ++i)
  {
    result[i] = i * i;
  }
  return result;
}

int main()
{
  // OK, notice no copies also!
  MathVector<int, 100> x1 = ints<int, 100>() + squares<int, 100>(); 

  // Should be invalid, ref to temp in returned object
  auto&& x2 = ints<int, 100>() + squares<int, 100>(); 
}
Clinton
  • 22,361
  • 15
  • 67
  • 163
  • Sorry, I've edited my question. They take them as arguments to `f`. – Clinton Oct 07 '11 at 00:28
  • 4
    Short answer: No. However, [Boost.Proto](http://www.boost.org/libs/proto/) has the same design situation, so you should see how that library works around it (`proto::deep_copy`). – ildjarn Oct 07 '11 at 00:28
  • Just for interest, could you paste some code that shows why you're doing this? (ie. implementation of A and f) – Ayjay Oct 07 '11 at 03:06
  • Ayjay: I've added code to the example. – Clinton Oct 07 '11 at 03:40

1 Answers1

5

Given any temporary object, it is always legal in C++ to extend the lifetime of that temporary by binding it to a const& or && variable. Ultimately, if you're dealing with lazy evaluation and the like, you have to ask the user not to use const auto & or auto &&. There's nothing in C++11 that allows you to forcibly prevent the user from doing so.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Nicol: Out of interest, what does binding temporaries to references offer that return value optimization doesn't? As in, where would `const auto& x = f(...)` or `auto&& x = f(...)` be any faster or otherwise more useful than `auto x = f(...)` (aside from cases where there is no move nor copy constructor defined)? – Clinton Oct 07 '11 at 00:58
  • @Clinton: If your compiler can elide the copy, then no, it won't be faster. But RVO and NRVO is still relatively new for many C++ programmers, so they tend to use `const&` when they don't need to. And normally, storing a temporary in a `const&` does no actual harm, so until now, there was no real problem. – Nicol Bolas Oct 07 '11 at 01:04