-4

How do I return an object from a constexpr function? According to this you can't use new but how do I do it then? Is it possible at all? I want to use the argument of the function to intialize an object and return it, but can't seem to figure out how.

Example:

struct Test {
    int a;
    constexpr Test (int b): a(b) {};
    Test(const Test& a);
};

Test::Test(const Test& t) {
    this->a = t.a;
}

constexpr Test set_test(int a) {
    return Test(a);
}

int main() {
    return 0;
}
Ferus
  • 1,080
  • 3
  • 12
  • 17
  • 7
    Why do your thoughts jump to `new` right away? – StoryTeller - Unslander Monica Feb 05 '18 at 14:19
  • 3
    What is the *actual* problem you want to solve? *Why* do you want to use `constexpr` functions and `new`? This is an [XY-problem question](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Some programmer dude Feb 05 '18 at 14:20
  • Well otherwise it would allocated on the stack and not survive after the function. – Ferus Feb 05 '18 at 14:21
  • 7
    A function can return an object by value. – Cris Luengo Feb 05 '18 at 14:21
  • _not survive after the function_ if you don't return a pointer/reference that's not a problem. –  Feb 05 '18 at 14:22
  • What do you mean by _object_? A class instance? – Ron Feb 05 '18 at 14:22
  • You're right, but If I return an object the compiler say: ```error: constexpr function never produces a constant expression``` even though the constructor is constexpr. – Ferus Feb 05 '18 at 14:24
  • 4
    In that case show us a minimal example which reproduces your error. – DeiDei Feb 05 '18 at 14:25
  • 3
    Operator `new` is radioactive. It must only be handled by experts who are trained in how to encase it in concrete and lead. I have been programming in C++ since cfront (1984), and I think I have used `new' just once since C++98. That was in writing a custom allocator. – Jive Dadson Feb 05 '18 at 14:26
  • 1
    *"f I return an object the compiler say: error: constexpr function never produces a constant expression even though the constructor is constexpr"* - I can't see it. Until humans develop telepathy, could you post a [mcve]? – StoryTeller - Unslander Monica Feb 05 '18 at 14:30
  • Please post a [mcve] as trying to guess the right answer to invisible code is not working for us. – Richard Critten Feb 05 '18 at 14:30
  • If we are going to help, we gots to have a [MCVE]. – Jive Dadson Feb 05 '18 at 14:31
  • Will try to fix one. – Ferus Feb 05 '18 at 14:31
  • Added example code. – Ferus Feb 05 '18 at 14:37
  • @JiveDadson and there was me thinking that your use of new was in conjunction with other descriptors like `newConnection()`meaning you weren't even using the keyword! :) – UKMonkey Feb 05 '18 at 14:38
  • So, what's wrong with the code? I copy/pasted it in [**ideone**](https://ideone.com/1BZhTp). It compiles and works. (Only, that I added output to prevent optimization.) – Scheff's Cat Feb 05 '18 at 14:42
  • The example you give compiles but does nothing. Post an example that demonstrates what you are trying to do, and what it actually does instead. It is not even clear to me why you want to define the function as constexpr. – Jive Dadson Feb 05 '18 at 14:43
  • I get the compile error specified above in clang with ```-std=c++11``` flag – Ferus Feb 05 '18 at 14:44

2 Answers2

2

I made a small addition to the exposed sample code to make use of set_test() and to prevent optimization of dead code:

#include <iostream>

struct Test {
    int a;
    constexpr Test (int b): a(b) {};
    Test(const Test& a);
};

Test::Test(const Test& t) {
    this->a = t.a;
}

constexpr Test set_test(int a) {
    return Test(a);
}

int main() {
  std::cout << "set_test(1).a: " << set_test(1).a << std::endl;
    return 0;
}

This works fine in ideone.

It states to use C++ (gcc 6.3).

Hence, I was looking for another online compile where I can choose clang and found Wandbox.

With clang HEAD 7.0.0 it fails to compile. If I got it right set_test() tries to use the copy constructor which is not constexpr.

Thus, I deleted the copy constructor. Now, it fails in return Test(a); because it tries to access the deleted copy constructor. Strange...

So, I finally provided a move-constructor

constexpr Test(Test &&test): a(test.a) { }

as replacement for the deleted copy constructor. Now, it compiles and works:

#include <iostream>

struct Test {
    int a;
    constexpr Test (int b): a(b) {}
    Test(const Test& a) = delete;
    constexpr Test(Test &&test): a(test.a) { }
};

#if 0
Test::Test(const Test& t) {
    this->a = t.a;
}
#endif // 0

constexpr Test set_test(int a) {
    return Test(a);
}

int main() {
  std::cout << "set_test(1).a: " << set_test(1).a << std::endl;
    return 0;
}

Output:

Start

set_test(1).a: 1

0

Finish

Life demo on Wandbox.


Out of curiosity, I modified the sample again to try out if making the copy-constructor a constexpr would fix as well. It does.

Life demo on Wandbox.

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
1

You can have a parameterized constexpr function of some type T returning a value of type T, T being a user defined class. Simple example:

#include <iostream>

struct A {
private:
    int x;
public:
    constexpr A(int x) : x(x) {};
    void print() {
        std::cout << x;
    }
};

constexpr A foo(int p) {
    A temp{ p };
    return temp;
}

int main() {
    A o = foo(123);
    o.print();
}

The whole point of the constexpr function is that its return type satisfies the constant expression requirements.

Ron
  • 14,674
  • 4
  • 34
  • 47