Calling Member Function of Number Literal

Calling member function of number literal

The answers by Greg Hewgill and icktoofay are correct in all ways, however, I'd like to get down a bit, abstraction-wise: Let's see what's really happening according to the javascript specification.

Section 7.8.3 of the spec defines numeric literals. We can see the following:

DecimalLiteral ::
DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt)
. DecimalDigits ExponentPart(opt)
DecimalIntegerLiteral ExponentPart(opt)

DecimalIntegerLiteral ::
0
NonZeroDigit DecimalDigits(opt)

A DecimalLiteral, a number, is a bunch of decimal digits, possibly followed by a dot, which is possibly followed by other digits (all of which can be followed by an exponent, e12 for instance). In other words, 42. is legal and equal to 42 and 3e2 is equal to 300.

Note how if we have a dot, we either expect it to be followed by more digits/exponent, or be followed by nothing. However, and this is the important part, the dot is part of the number. Remember this as we move to look how the dot operator, obj.prop, is dealt with.

Section 11.2.1, Property Accessors describes the dot and bracket notation for member access:

MemberExpression . IdentifierName

CallExpression is for function calls, which we don't care about. Notice how we're expecting a MemberExpression (which can be a DecimalLiteral - but don't take my word for it, look and see whether I'm right).

See that little dot? It's logical to jump forward and say "well, there's a dot in the scheme here...and there's a dot in 4.foo...so why is there an error?" Alas my hypothetical friend whom I use for these sentences, you forgot how the DecimalLiteral looks like! Let's go over two examples and see what happens.

42.foo
^

The caret represents the character we're on. So far, we're inside DecimalLiteral / DecimalIntegerLiteral / NonZeroDigit (that's quite a mouthful). Let's move to the next character:

42.foo
^

Still part of the number, a perfectly valid DecimalDigit.

42.foo
^

ok, so we're out of the DecimalIntegerLiteral part. Here's the same diagram on the scheme:

DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt)
^

So we're on a dot, which is a perfectly valid part of a number. Now we consume it, as part of the number, and move on:

42.foo
^

f is neither part of DecimalDigits nor of ExponentPart, we're out of the number now. So...what now? What's that f? It's not part of anything. Maybe it's a property accessor? Let's take a look at the scheme:

MemberExpression . IdentifierName
^

We're definitely on MemberExpression, but we don't have a dot which follows it - that dot is already part of the number. We've reached a syntactical error: we stop execution and throw it. Hopefully you don't live in a glass house.

Hopefully now you understand why 42..foo works. Once we're out of the MemberExpression, we face another dot:

              42..foo
^
MemberExpression . IdentifierName
^

Followed by a perfectly legal IdentifierName.

Of course, there're several other ways to separate the dot from the number. One way, as you showed, is to surround the literal in parentheses: (42).foo. When we've reached the parentheses end, we're out of the MemberExpression, and on the dot. Another way is to insert a space: 42 .foo, since a space can't be part of the number, and it's neutral for the parser, so it won't raise an error.

Does a temporary object gets created by calling a function with a numeric literal?

Semantically (forgetting about inlining, optimization and stuff) the first snippet does not require a temporary.

void f(int a){...}

When you call this function as in f(3), an integer object is created using (pseudo) copy-constructor of int to be used as function argument. This becomes a local parameter to the function, and it's life-time ends when function returns.

Meanwhile, the second snippet

void f(int&& a){...}

requires calling code to create a temporary int variable (as you can't bind a reference of any kind to numeric literal). After that an rvalue reference is bound to created temporary.

And to your question of 'efficiency', compilers do not select function overloads based on efficiency. They do this based on a certain ranking of conversions, and in your case, copy and a reference binding have the same rank. You can read more about overload resolution here: https://en.cppreference.com/w/cpp/language/overload_resolution

Cannot call toString() on numeric constant in Javascript

The first dot is the decimal mark. You need a second one to access the property:

5..toString();

Array Member function on a literal

ColdFusion does not support calling methods on a literal, no.

Ref: Member functions cannot be called on literals, which says:

This should work:

"lowercase".ucase()

It currently doesn't.

Write a function that only accepts literal `0` or literal `1` as argument

In C++20 you can use the consteval keyword to force compile time evaluation. With that you could create a struct, which has a consteval constructor and use that as an argument to a function. Like this:

struct S
{
private:
int x;
public:
S() = delete;

consteval S(int _x)
: x(_x)
{
if (x != 0 && x != 1)
{
// this will trigger a compile error,
// because the allocation is never deleted
// static_assert(_x == 0 || _x == 1); didn't work...
new int{0};
}
}

int get_x() const noexcept
{
return x;
}
};

void func(S s)
{
// use s.get_x() to decide control flow
}

int main()
{
func(0); // this works
func(1); // this also works
func(2); // this is a compile error
}

Here's a godbolt example as well.

Edit:

Apperently clang 10 does not give an error as seen here, but clang (trunk) on godbolt does.

Calling a member function by address (C++ Reflection attempt)

Grab this:

#include <string>

class Primitive
{
private:
std::string name;
public:
Primitive(std::string name) : name(name) {}
};

template<typename T>
class ClassMethod : Primitive
{
private:
void (T::*methodAddress)(); // used as a "generic" function pointer
T& targetClass;
public:
template<typename R, typename ...Args> // no need for casting to void*
// and also check type - `methodAddress` is a member function specifically on `T`, not any abstract pointer...
ClassMethod(std::string name, T& instance, R (T::*methodAddress)(Args...)) :
Primitive(name),
// take a reference, unless you accept `nullptr`... I do not believe you do...
targetClass(instance),
// I do not believe this is very valid, but "will work".
methodAddress(reinterpret_cast<void(T::*)()>(methodAddress))
{
// all those out of class template deifinitions are confusing
// let's move them inside!
}

template<typename ReturnType, typename ...Args>
ReturnType Invoke(Args... args)
{
ReturnType (T::*funcionPointer)(Args...) = reinterpret_cast<ReturnType (T::*)(Args...)>(methodAddress);
// forward arguments
return (targetClass.*funcionPointer)(std::forward<Args...>(args)...);
// when targetClass is a pointer, then
// `*targetClass.*funcionPointer` is equal to `*(targetClass.*funcionPointer)` !!
// you want `((*targetClass).*functionPointer)` or just `targetClass->*funcionPointer
}
};

// abstract example

#include <iostream>
#include <vector>

struct A {
double func(int a) {
std::cout << "func(" << a << ") ";
return 3.41;
}
int fun2(char b) {
std::cout << "fun2('" << b << "') ";
return 50;
}
};

int main() {
A a;
std::vector<ClassMethod<A>> v;
v.emplace_back("func", a, &A::func);
v.emplace_back("fun2", a, &A::fun2);
auto rd = v[0].Invoke<double>(5); // you have to specify return type
auto ri = v[1].Invoke<int>('a'); // you have to specify return type
std::cout << rd << " " << ri << "\n";
}

tested on godbold prints:

func(5) fun2('a') 3.41 50

The function definitions outside of class ClassMethod definition are just confusing, with those template<> template<> stuff. Just put them inside class definition.

Calling non-static member function outside of object's lifetime in C++17

It’s true that trivial destructors do nothing at all, not even end the lifetime of the object, prior to (the plans for) C++20. So the question is, er, trivial unless we suppose a non-trivial destructor or something stronger like delete.

In that case, C++17’s ordering doesn’t help: the call (not the class member access) uses a pointer to the object (to initialize this), in violation of the rules for out-of-lifetime pointers.

Side note: if just one order were undefined, so would be the “unspecified order” prior to C++17: if any of the possibilities for unspecified behavior are undefined behavior, the behavior is undefined. (How would you tell the well-defined option was chosen? The undefined one could emulate it and then release the nasal demons.)



Related Topics



Leave a reply



Submit