smilingthax
smilingthax

Reputation: 5724

decltype(function) as class member

I have:

int foo(int x) { return x+1; }

struct Bar {
  decltype(foo) operator();
};

int main() {
  Bar bar;
  printf("%d\n",bar(6));
}

which results in the slightly startling compiler error message (g++ 4.6.1):

error: declaration of 'operator()' as non-function

When changing the member name to

  decltype(foo) blubb;

and using it results in a linker error:

undefined reference to `Bar::blubb(int)'

Is this expected behaviour?

Upvotes: 6

Views: 1375

Answers (3)

emsr
emsr

Reputation: 16333

This should work. I just used it here to capture whatever gobbledygook std::bind was going to give me:

class RiceFadingModel::Impl
{
public:
  Impl(double K, double A)
  : //...
    _M_re{system_now()},
    _M_rd{_M_nu, _M_sigma},
    _M_gen{std::bind(_M_rd, _M_re)}
  { }


private:

//...

  std::default_random_engine _M_re;
  ///  The underlying Rice distribution.
  __gnu_cxx::__rice_distribution<double> _M_rd;
  ///  The variate generator built from the pseudo-random number engine and the Rice distribution.
  decltype(std::bind(_M_rd, _M_re)) _M_gen;
};

This works like a charm on gcc-4.7. Now that I think about it I built it on mingw with gcc-4.5 too.

Upvotes: 0

PlasmaHH
PlasmaHH

Reputation: 16046

It seems that you want to "copy" the signature of another function to create a function with the same signature. Since decltype(foo) is indeed the type of the function (and not a pointer to that function, which would be decltype(&foo) and would lead to a pointer declaration), you can use it to declare a function with the same signature as another function.

As indicated by the linker error:

undefined reference to `Bar::blubb(int)'

this will already work fine with your compiler. However it seems that gcc did not yet fully implement this part of the standard, as it will not accept the syntax for the same thing with a function call operator. Clang btw. will happily accept it and the link then errors out with

undefined reference to `Bar::operator()(int)'

Your question about why that linker error exists indicates a misunderstanding of what decltype really does.

It will just evaluate to a type, not more. The definition of blubb is in no way tied to the definition of foo. This might be clearer when writing it like

typedef decltype(foo) x; 
x blubb;

You can now alternatively typedef x to be explicitly the function type, which will not in any way change what blubb is. You still need to define it. And since there is no syntax to define it using decltype, you explicitly have to write it as

int Bar::operator()(int) {
...
}

which will likely and unfortunately defeat the purpose/benefit of using decltype for the declaration, as it will not allow you to automatically "copy" a signature.

Upvotes: 5

Sebastian Mach
Sebastian Mach

Reputation: 39089

This is a wild guess based on observing your usage of printf here:

printf("%d\n",bar(6));

This lets me assume you really want the return type of the function, not the type of the function. If so, then you use decltype wrong. You get the return type of the function by "simulating" the usage of the function, i.e.

decltype(foo(0)) operator() (int);

should be the right thing for you. Otherwise, if that was not your attention, you are skating on thin ice by giving a function type (and not function return type) to the %d specifier.

Generally, the meaning of decltype is: decltype(@) gives the static type of the expression @.

Upvotes: 2

Related Questions