9

Can one in C++11 somehow in gcc mark a function (not a class method) as const telling that it is pure and does not use the global memory but only its arguments?

I've tried gcc's __attribute__((const)) and it is precisely what I want. But it does not produce any compile time error when the global memory is touched in the function.

Edit 1

Please be careful. I mean pure functions. Not constant functions. GCC's attribute is a little bit confusing. Pure functions only use their arguments.

moswald
  • 11,491
  • 7
  • 52
  • 78
Cartesius00
  • 23,584
  • 43
  • 124
  • 195
  • nor sure what you mean, but have you tried `constexpr` – Cheers and hth. - Alf Dec 02 '12 at 22:55
  • That's NOT it. I mean pure not constant. GCC's attributes are a little bit confusingly named. – Cartesius00 Dec 02 '12 at 23:08
  • 2
    I think you need to rephrase your question, because you have the right attribute. That it doesn't produce the warning you want is a different matter -- at least when taking your question at face value. – Luc Danton Dec 02 '12 at 23:19
  • @LucDanton Yes, formally you're absolutely right. But it surprised me that it does not produce any warning nor compile error. And I'd like to know if there is any way how to check it in compile time. – Cartesius00 Dec 02 '12 at 23:21
  • Im getting interested. Can you please explain how you did this normally, NOT in C++11? – Barney Szabolcs Dec 02 '12 at 23:26
  • @BarnabasSzabolcs I don't know if C++ is able to do that in any version. It's something that is normal and natural in the functional world on the other hand. – Cartesius00 Dec 02 '12 at 23:28
  • Well, interesting. In this case, I think some others from the functional world could help with this problem, if you are not satisfied with sftrabbit's answer. This last comment of yours was much more enlightening for me than the actual text in the question. You might want to include this info there, along with a tag of your favourite functional programming tags, with explanation... – Barney Szabolcs Dec 02 '12 at 23:34

3 Answers3

7

Are you looking for constexpr? This tells the compiler that the function may be evaluated at compile time. A constexpr function must have literal return and parameter types and the body can only contain static asserts, typedefs, using declarations and directives and one return statement. A constexpr function may be called in a constant expression.

constexpr int add(int a, int b) { return a + b; }

int x[add(3, 6)];

Having looked at the meaning of __atribute__((const)), the answer is no, you cannot do this with standard C++. Using constexpr will achieve the same effect, but only on a much more limited set of functions. There is nothing stopping a compiler from making these optimizations on its own, however, as long as the compiled program behaves the same way (the as-if rule).

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • Thank you. Attribute `constexpr` is almost useless. Maybe let's wait a little bit more. Maybe some other `gcc`-specific attribute could help. – Cartesius00 Dec 02 '12 at 23:19
  • [clang *does* detect and reject modifications](http://goo.gl/QFpk6F) to globals in a `constexpr` function. gcc 5.3, and gcc6-snapshot just compile the function as written. IDK how fully clang enforces [constexpr](http://en.cppreference.com/w/cpp/language/constexpr), or if you can sneak some violations past it. Note that C++14 changes the constexpr rules: C++14 has a blacklist of disallowed things, rather than a restrictive whitelist. – Peter Cordes Feb 29 '16 at 08:30
  • 2
    constexpr functions are NOT pure – MikeMB Feb 07 '18 at 08:50
  • 1
    ... and pure functions are not necessarily constexpr. This is just a wrong answer – Dodgie Jun 17 '20 at 15:16
3

Because it has been mentioned a lot here, lets forget about Meta programming for now, which is pure functional anyway and off topic. However, a constexpr function foo can be called with non constexpr arguments and in this context foo is actually a pure function evaluated at runtime (I am ignoring global variables here). But you can write many pure functions that you cannot make constexpr, this includes any function throwing exceptions for example.

Second I assume the OP means marking pure as an assertion for the compiler to check. GCC's pure attribute is the opposite, a way for the coder to help the compiler.

While the answer to the OP's question is NO, it is very interesting to read about the history of attempts to introduce a pure keyword (or impure and let pure be the default).

The d-lang community quickly figured out that the meaning of "pure" is not clear. Logging should not make a function impure. Mutable variables that do not escape the function call should be allowed in pure functions. Equal return values having different addresses should not be considered impure. But D goes even further than that in stretching purity.

So the d-lang community introduced the term "weakly pure" and "strongly pure". But later disputes showed that weak and strong is not black and white and there are grey zones. see purity in D

Rust introduced the "pure" keyword early on; and they dropped it because of its complexity. see purity in Rust.

Among the great benefits of a "pure" keyword there is an ugly consequence though. A templated function can be pure or not depending on its type parameters. This can explode the number of template instantiations. Those instantiations may only need to exist temporarily in the compiler and not get into the executable but they can still explode compile times.

A syntax highlighting editor could be of some help here without modifying the language. Optimizing C++ compilers do actually reason about the pureness of a function, they just do not guarantee catching all cases.

I find it sad that this feature seems to have low priority. It makes reasoning about code so much easier. I would even argue that it would improve software design by the way it incentivizing programmers to think differently.

Patrick Fromberg
  • 1,313
  • 11
  • 37
2

using just standard C++11:

namespace g{ int x; }

constexpr int foo()
{
    //return g::x = 42;  Nah, not constant
    return 42;      // OK
}

int main()
{}

here's another example:

constexpr int foo( int blah = 0 )
{
    return blah + 42;      // OK
}

int main( int argc, char** )
{
    int bah[foo(2)];            // Very constant.
    int const troll = foo( argc );  // Very non-constant.
}

The meaning of GCC's __attribute__( const ) is documented in the GNU compiler docs as …

Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the pure attribute below, since function is not allowed to read global memory.

One may take that to mean that the function result should only depend on the arguments, and that the function should have no side effects.

This allows a more general class of functions than C++11 constexpr, which makes the function inline, restricts arguments and function result to literal types, and restricts the "active" statements of the function body to a single return statement, where (C++11 §7.1.5/3)

— every constructor call and implicit conversion used in initializing the return value (6.6.3, 8.5) shall be one of those allowed in a constant expression (5.19)

As an example, it is difficult (I would think not impossible, but difficult) to make a constexpr sin function.

But the purity of the result matters only to two parties:

  • When known to be pure, the compiler can elide calls with known results.
    This is mostly an optimization of macro-generated code. Replace macros with inline functions to avoid silly generation of identical sub-expressions.

  • When known to be pure, a programmer can remove a call entirely.
    This is just a matter of proper documentation. :-)

So instead of looking for a way to express the purity of e.g. sin in the language, I suggest just avoid code generation via macros, and document pure functions as such.

And use constexpr for the functions where it's practically possible (unfortunately, as of Dec. 2012 the latest Visual C++ compiler doesn't yet support constexpr).


There is a previous SO question about the relationship between pure and constexpr. Mainly, every constexpr function is pure, but not vice versa.

Community
  • 1
  • 1
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331