4

I'm working with an expression template class which should not be instantiated to avoid dangling references. But I'm temped to declare a variable with auto and 'auto' create a named instance of a temporary class.

How can I disable auto declaration of temporary class in the following code?

class Base
{
};

class Temp : public Base
{
public:
    Temp()         {}
    Temp(int, int) {}
    Temp(const Temp&) = default;
    Temp(Temp&&)      = default;
};

Temp testFunc(int a, int b) {
    return Temp{a,b};
}

int main() {
    Base a = testFunc(1,2); // this should work
    auto b = testFunc(1,2); // this should fail to compile
    return 0;
}

2 Answers2

1

You seem to want to prevent users from using auto on a particular type. That's not possible in any version of C++. If it is legal C++ for a user to write T t = <expr>;, where T is the type of <expr>, then it will be legal for a user to write auto t = <expr>; (ignoring class data members). Just as you cannot forbid someone from passing <expr> to a template function using template argument deduction.

Anything you do to prevent auto usage will also inhibit some other usage of the type.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • It's good to know it is not possible. However I hope controlling auto becomes possible someday because expression template is very useful while 'auto' makes it error prone. Are there different way than expression template, which guarantee elision of intermediate prvalue construction? – user10189446 Aug 07 '18 at 05:40
0

One option would be to make Temp's constructors private, move testFunc inside the Temp class and make it static. This way you can still instantiate Base, but auto would fail because you would be calling a private constructor:

class Base
{
};

class Temp : public Base
{
    Temp()         {}
    Temp(int, int) {}
    Temp(const Temp&) = default;
    Temp(Temp&&)      = default;

public:

    static Temp testFunc(int a, int b)
    {
        return Temp{a,b};
    }
};

int main() {
    Base a = Temp::testFunc(1,2); // this should work
    auto b = Temp::testFunc(1,2); // this should fail to compile
    return 0;
}

Demo

cantordust
  • 1,542
  • 13
  • 17
  • What good is that, exactly? You wouldn't be able to write `Temp a = ...` for the same reason `auto` won't work. Any attempt to use `testFunc` and store the results in a variable will result in slicing. How does this help? Also, C++17's guaranteed elision confounds you; since `testFunc` returns a prvalue, `auto b = ...` will compile just fine in a valid C++17 compiler. It doesn't need to call a copy constructor. – Nicol Bolas Aug 07 '18 at 04:29
  • `You wouldn't be able to write Temp a = ... for the same reason auto won't work` A valid point. However, my interpretation of the question was that you should not be able to instantiate `Temp` directly *at all*, but should be able to instantiate `Base`. This point has been clarified in the latest comment. Re guaranteed copy elision, this could perhaps be solved by explicitly returning `Temp&&` from `testFunc`, although in that case you have to get instances with `Temp&& c = Temp::testFunc(1,2)`, which might not be ideal. – cantordust Aug 07 '18 at 06:18
  • You can't return a reference to a stack variable. – Nicol Bolas Aug 07 '18 at 13:34
  • Hmm, true, I didn't think that all the way through. – cantordust Aug 07 '18 at 15:03