5

Why in the following example the compiler fails to bind the very same static function if it's declared within a class scope?

#include <vector>
#include <iostream>

struct Foo
{
static constexpr int GetSize()
{
    return 5;
}
static void ProcessArrayWrong(int(&indices)[Foo::GetSize()])
{
    for(int i =0; i < Foo::GetSize(); i++)
    {
        indices[i]++;
    }
}
};

static void ProcessArray(int(&indices)[Foo::GetSize()])
{
    for(int i =0; i < Foo::GetSize(); i++)
    {
        indices[i]++;
    }
}

int main(int argc, char* argv[])
{
    int foo[Foo::GetSize()] = {1,2,3,4,5};

    for(int i =0; i < Foo::GetSize(); i++)
    {
        std::cout << foo[i]++ << std::endl; 
    }
    ProcessArray(foo);
    ProcessArrayWrong(foo); // fails here
    for(int i =0; i < Foo::GetSize(); i++)
    {
        std::cout << foo[i]++ << std::endl; 
    }
    return 0;
}

The error is:

error: non-const lvalue reference to type 'int [*]' cannot bind to a value of unrelated type 'int


It seems that the question linked in the comments is explaining why it's an error. Thanks. It'd be great to know at this point, in regards with the answers provided in the linked post:

  1. Why exactly the "template trick" works? I suspect because template code requires an additional pass to be compiled, but I would rather have a more clear opinion on this.
  2. Is declaring the function has template causing any non wanted or non expected behavior or is it safe to use?
4
  • 2
    Probably this: stackoverflow.com/a/16493853/206404 Commented Mar 30, 2020 at 13:24
  • Thanks @Stephen Newell: I think you're right. Commented Mar 30, 2020 at 13:28
  • The "template trick" is required because int(&indices)[Foo::GetSize()] is an incomplete type, a reference to an array of "who knows how big" at compile-time. Commented Mar 30, 2020 at 16:16
  • Thanks, I see. Is it safe to use that? or is there any non obvious downside? Commented Mar 30, 2020 at 16:19

1 Answer 1

1

The “template trick” works because templates (and member functions of class templates) are already instantiated on-demand. While the standard doesn’t actually say that that property allows member functions to be used in things like array sizes, neither is there any actual rule against it in the non-template case and common implementation strategies support the trick as a side benefit.

Given that the current opinion is that the (class) template behavior is more correct, it’s probably safe to rely on it. Moreover, the standard library declares all sorts of things as templates invisibly, indicating that it generally doesn’t cause problems. (You can even use things like explicit instantiations to keep the function template’s definition elsewhere.)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.