Get Name of X When Defining '(<-' Operator

How do I access the name of the variable assigned to the result of a function within the function?

I think that it's not strictly possible, as other solutions explained, and the reasonable alternative is probably Yosi's answer.

However we can have fun with some ideas, starting simple and getting crazier gradually.


1 - define an infix operator that looks similar

`%<-add_str%` <- function(e1, e2) {
e2_ <- e2
e1_ <- as.character(substitute(e1))
eval.parent(substitute(e1 <- paste0(e1_,e2_)))
}

a %<-add_str% "b"
a
# "ab"

2 - Redefine := so that it makes available the name of the lhs to the rhs through a ..lhs() function

I think it's my favourite option :

`:=` <- function(lhs,rhs){
lhs_name <- as.character(substitute(lhs))
assign(lhs_name,eval(substitute(rhs)), envir = parent.frame())
lhs
}

..lhs <- function(){
eval.parent(quote(lhs_name),2)
}

add_str <- function(x){
res <- paste0(..lhs(),x)
res
}

a := add_str("b")
a
# [1] "ab"

There might be a way to redefine <- based on this, but I couldn't figure it out due to recursion issues.


3 - Use memory address dark magic to hunt lhs (if it exists)

This comes straight from: Get name of x when defining `(<-` operator

We'll need to change a bit the syntax and define the function fetch_name for this purpose, which is able to get the name of the rhs from a *<- function, where as.character(substitute(lhs)) would return "*tmp*".

fetch_name <- function(x,env = parent.frame(2)) {
all_addresses <- sapply(ls(env), pryr:::address2, env)
all_addresses <- all_addresses[names(all_addresses) != "*tmp*"]
all_addresses_short <- gsub("(^|<)[0x]*(.*?)(>|$)","\\2",all_addresses)

x_address <- tracemem(x)
untracemem(x)
x_address_short <- tolower(gsub("(^|<)[0x]*(.*?)(>|$)","\\2",x_address))

ind <- match(x_address_short, all_addresses_short)
x_name <- names(all_addresses)[ind]
x_name
}

`add_str<-` <- function(x,value){
x_name <- fetch_name(x)
paste0(x_name,value)
}

a <- NA
add_str(a) <- "b"
a

4- a variant of the latter, using .Last.value :

add_str <- function(value){
x_name <- fetch_name(.Last.value)
assign(x_name,paste0(x_name,value),envir = parent.frame())
paste0(x_name,value)
}

a <- NA;add_str("b")
a
# [1] "ab"

Operations don't need to be on the same line, but they need to follow each other.


5 - Again a variant, using a print method hack

Extremely dirty and convoluted, to please the tortured spirits and troll the others.

This is the only one that really gives the expected output, but it works only in interactive mode.

The trick is that instead of doing all the work in the first operation I also use the second (printing). So in the first step I return an object whose value is "b", but I also assigned a class "weird" to it and a printing method, the printing method then modifies the object's value, resets its class, and destroys itself.

add_str <- function(x){
class(x) <- "weird"
assign("print.weird", function(x) {
env <- parent.frame(2)
x_name <- fetch_name(x, env)
assign(x_name,paste0(x_name,unclass(x)),envir = env)
rm(print.weird,envir = env)
print(paste0(x_name,x))
},envir = parent.frame())
x
}

a <- add_str("b")
a
# [1] "ab"

(a <- add_str("b") will have the same effect as both lines above. print(a <- add_str("b")) would also have the same effect but would work in non interactive code, as well.

Defining a functional operator's result via an expression stored in a variable is not working

This is a common source of confusion.

In your second example the formal parameters x and y of your procedure have no connection to the names x and y present in the expression assigned temp.

The usual way to accomplish the second example is to use the unapply command.

temp := x^2 + y^2;

2 2
temp := x + y

f := unapply(temp, [x,y]);

f := proc (x, y) options operator, arrow; y^2+x^2 end proc

f(1, 2);

5

One more general (and also more advanced) approach is to substitute into a template with the expression(s) containing the matching names. Eg,

g := subs(__dummy=temp,
(x,y)->__dummy);

g := proc (x, y) options operator, arrow; y^2+x^2 end proc

g(1, 2);

5

Operator overloading confusion

The prefix -- operator takes no arguments. Its definition should be as follows:

public:
/* ... declarations of X ... */
X& operator--();
};

And similarly when implementing it:

#include "X.h"
namespace X {
X& X::operator--() {/*...*/}
}

Implementing overloads for and operators in a template class

Turning up the warning level of the compiler helps. By using -Wall with g++, I get the following warnings before the linker error.

socc.cc:13:58: warning: friend declaration ‘std::istream& operator>>(std::istream&, MyClass<MYTYPE>&                    )’ declares a non-template function [-Wnon-template-friend]
friend istream& operator>>(istream&, MyClass<MYTYPE>&);
^
socc.cc:13:58: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
socc.cc:14:57: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, MyClass<MYTYPE> ’ declares a non-template function [-Wnon-template-friend]
friend ostream& operator<<(ostream&, MyClass<MYTYPE>);

You need to use function templates for the operator>> and operator<< functions. You can declare them before the definition of the class with:

// Forward the class template.
template <class MYTYPE> class MyClass;

// Declare the function templates.
template <class MYTYPE>
std::istream& operator>>(std::istream&, MyClass<MYTYPE>&);

template <class MYTYPE>
std::ostream& operator<<(st::ostream&, MyClass<MYTYPE>);

Then, you'll have to use the friend declaration with the appropriate template parameter.

// This makes sure that operator>><int> is not a friend of MyClass<double>
// Only operator>><double> is a friend of MyClass<double>
friend std::istream& operator>><MYTYPE>(std::istream&, MyClass<MYTYPE>&);
friend std::ostream& operator<<<MYTYPE>(std::ostream&, MyClass<MYTYPE>);

Here's an updated version of your code that builds for me. I haven't tried to run it.

#include <iostream>
#include <string>
using namespace std;

template <class MYTYPE> class MyClass;

template <class MYTYPE>
std::istream& operator>>(std::istream&, MyClass<MYTYPE>&);

template <class MYTYPE>
std::ostream& operator<<(std::ostream&, MyClass<MYTYPE>);

template <class MYTYPE>
class MyClass {
MYTYPE *myVector;
int dim;
string name;
public:
MyClass(int, string);
MyClass() {};

friend std::istream& operator>><MYTYPE>(std::istream&, MyClass<MYTYPE>&);
friend std::ostream& operator<<<MYTYPE>(std::ostream&, MyClass<MYTYPE>);
};

template <class MYTYPE>
MyClass<MYTYPE>::MyClass(int x, string y) {
dim = x;
name = y;
myVector = new MYTYPE[dim];
}

template <class MYTYPE>
std::istream& operator>>(std::istream& X, MyClass<MYTYPE>& a){
cout<<"Reading vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++){
cout<<a.name<<'['<<indice<<"]= ";
X >> a.myVector[indice];
}
return X;
}

template <class MYTYPE>
std::ostream& operator<<(std::ostream& X, MyClass<MYTYPE> a){
X<<"Vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++)
X<<a.myVector[indice]<<' ';
X<<endl;
return X;
}

int main() {
MyClass<int> object(4, "Ints vector");
MyClass<string> object2(5, "String vector");
cin >> object;
cin >> object2;
cout << object;
cout << object2;
system("pause");
return 0;
}

Trouble with inheritance of operator= in C++

If you do not declare copy-assignment operator in a class, the compiler will declare one for you implicitly. The implicitly declared copy-assignment operator will hide any inherited assignment operators (read about "name hiding" in C++), meaning that any inherited assignment operators will become "invisible" to the unqualified name lookup process (which is what happens when you do b = c), unless you take specific steps to "unhide" them.

In your case, class B has no explicitly declared copy-assignment operator. Which mean that the compiler will declare

B& B::operator =(const B&)

implicitly. It will hide the operator inherited from A. The line

b = c;

does not compile, because, the only candidate here is the above implicitly declared B::operator = (the compiler told you about that already); all other candidates are hidden. And since c is not convertible to B&, the above assignment does not compile.

If you want your code to compile, you can use using-declaration to unhide the inherited A::operator = by adding

using A::operator =;

to the definition of class B. The code will now compile, although it won't be a good style. You have to keep in mind that in this case the b = c assignment will invoke A::operator =, which assigns only the A portions of the objects involved. (But apparently that is your intent.)

Alternatively, in cases like this you can always work around name hiding by using a qualified version of the name

b.A::operator =(c);

no match for 'operator*' in C++

The error means what it says: There is no operator* for int * X and no operator+ for X + int. You only have overloaded operators for X * int, X * X and X + X.

You can add a converting constructor and make the operators free functions, then implicit conversions work on both operands (note that the getter should be const):

#include <iostream>

class X {
public:
X(double length=0.0) : length(length) {} // <- converting constructor
double getLength() const { // <- const !!!
return length;
}
void setLength(double len) {
length = len;
}
private:
double length; // Length of a box
};

X operator*(const X& a,const X& b){
return {a.getLength() * b.getLength()};
}

X operator+(const X& a,const X& b){
return {a.getLength() + b.getLength()};
}

int main() {
X ob2{6.0};
X ob3{12.0};
X ob3;

ob1 = ob2 + 2*ob3;
ob1 = ob2*2 + ob3;
ob1 = (ob2 + 2) *ob3;

std::cout << "length of Box : " << ob1.getLength() << std::endl;
}

overloading [][] operators in c++

There is no operator [][], so you need to overload the [] operator twice: once on the matrix, returning a surrogate object for the row, and once for the returned surrogate row:

// Matrix's operator[]
const row_proxy operator[](int row) const
{
return row_proxy(this, row);
}
// Proxy's operator[]
const real operator[](int col) const
{
// Proxy stores a pointer to matrix and the row passed into the first [] operator
return ((this->row >= 0 && this->row <= 2) && (col >= 0 && col <= 2)) ? this->matrix->_data[this->row][col] : 0.0f;
}


Related Topics



Leave a reply



Submit