I am working on a class that has a method with the following signature:
operator const std::string & () const
It's documented as "cast to string operator".
I am wondering how to effectively invoke it. Unfortunately the following expression:
std::string(foo)
produces this error:
some_test.cpp:13:41: error: no matching function for call to'
std::basic_string<char>::basic_string(Foo (&)(std::string))'
Considering that foo is of type Foo, declared and instantiated as Foo foo(std::string(filename))
being a begginner of C++, this leaves me a bit confused. Any hints on what this means?
foo is of type Foo, declared and instantiated as Foo foo(std::string(filename))
That's a function declaration, interpreting filename as the name of a function parameter, equivalent to
Foo foo(std::string filename);
A variable declaration would look like
Foo foo(filename);
or, if you needed an explicit conversion (which you probably don't here)
Foo foo{std::string(filename)}; // C++11 or later
Foo foo = Foo(std::string(filename)); // historic dialects
If you question was about the usage of operator const std::string & () const, it is quite simple : this operator is used when you need to convert to a std::string. Example :
Foo foo(filename);
std::string s = foo; // uses the declared operator const std::string & () const
Related
I encountered this method and I'm not sure how to interpret it:
const char(*get_foo(int par))[38]
{
return foo;
}
the par parameter is not used in the function...
And foo is defined as:
static const char bar[] = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char(*foo)[38] = &bar;
get_foo, foo, and bar are all members of the same class.
Also, when get_foo is called, its return value is stored in a const ushort* value:
const ushort* baz = *instant->get_foo(some_value);
I didn't see that syntax before and can't understand this method declaration, what are the different parts that make up this declaration and explain how to read it?
This is a function that takes an int and returns a pointer-to-array containing 38 const char types. It's not clear why the par parameter is not used, that would be a question for the original author.
A function like this should be read:
const char(*get_foo(int par))[38]
^~~~~~~~~~~~~~~~ (1)
^~~~~~~~~~~~ ^~~~~ (2)
The name of the function is get_foo, with function parameter int named par
The return type is const char(*)[38] -- which is a pointer to an array of char char containing 38 entries
Due to operator precedence in C++, it leads to types that look obfuscated like this, since otherwise it would introduce syntactic ambiguities. It would be easier to read had the author of the code simply used an alias:
using array_type = const char(*)[38];
array_type get_foo(int par);
which is equivalent to const char(*get_foo(int par))[38]
With g++, this is a legal declaration:
class foo
{
public:
foo();
&operator int(); // this fails with Clang
};
This is a simplified example of my real code, which looks more like
template <class VAR_TYPE> class Foo : public Bar<VAR_TYPE>
{
public:
Foo();
// [...] more constructors here
&operator const VAR_TYPE () const; // this fails with Clang
// [...] more stuff (a lot)
};
Trying to compile this with Clang yields the following error:
error: cannot specify any part of a return type in the declaration of
a conversion function; put the complete type after 'operator'
I've found arguments that the GCCs use of & here is forbidden, as it violates the language definition 12.3.2.1
[...] No return type can be specified. If a conversion function is a
member function, the type of the conversion function (8.3.5) is
“function taking no parameter returning conversion-type-id”. [...]
Question 1.
What exactly does the GCC implementation do? From my testing, I suspect it to be equivalent to operator int& ();, but please correct me if I'm wrong or if I miss some additional functionality.
Question 2.
In my (legacy) code, it's actually &operator const VAR_TYPE() const;. Given my assumption from Question 1 is true, this would be equivalent to operator const VAR_TYPE&() const;. What could be the purpose of returning a const reference instead of a non-reference copy and can this be somehow exploited to give write-access to underlying data-structures like array/vector-elements?
Question 3.
Is this really illegal by the language definition? The cited text only talks about return types. & is not a type. It's a lexical element which needs to be combined with a normal type-specifier to become a type. But I can't find an extensive explanation of & in the language definition.
This is an overloaded operator contained in a class:
inline operator const FOO() const { return _obj_of_type_FOO; }
I cannot for the life of me understand:
How I would invoke this operator?
What would be its return value?
[Secondary] Whether making it inline affects anything apart from efficiency?
That expression looks like a declaration of a conversion operator if Foo is a type and it is inside a class. The second const (the one closer to the opening curly bracket) means that the conversion can be called on const instances. Let us say the class is C. You can think of a conversion operator as a constructor outside a class. For example, you can't add constructors to the class std::string, but you can add a conversion operator to std::string to your classes. The result is that you can construct std::string from your class instance.
1) How to invoke the conversion operator: by constructing a value of type Foo from a C, for example:
Foo foo = c (where c is an instance of C, the class that declares the conversion operator). Mind you that the invocation of the conversion can happen implicitly. If you have, for example, void funOnFoo(Foo v); and an instace c of C, this might implicitly call operator const Foo: funOnFoo(c). Whether this actually does, depends on the usual things: Whether there are other overloads of funOnFoo, other conversions for C, etc.
2) The return value is const Foo
3) inline means the same thing as for any function, in particular, does not affect overload resolution
I'd like to pass a temporary object(std::string for example) to the constructor of my object:
class MyClass{
public:
MyClass(string a):
a(a)
{
}
string a;
};
int main(int argc, char *argv[]){
MyClass a(string());
cout<<a.a<<endl;
return 0;
}
But I receive this error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:28:11: error: request for member ‘a’ in ‘a’, which is of non-class type ‘MyClass(std::string (*)()) {aka MyClass(std::basic_string<char> (*)())}’
Everything works ok if I pass anything to the constructor of temporary object(for example string("")). Why?
This is an instance of what has been dubbed C++'s most vexing parse. The compiler interprets
MyClass a(string());
as the prototype of a function named a returning a MyClass and taking an unnamed string as a parameter.
You can disambiguate it by putting parenthesis around the call to strings constructor:
MyClass a((string()));
Or, as long as MyClass has an accessible copy constructor:
MyClass a = string();
Update for C++11
You can also disambiguate with the universal initialisation syntax, as long as your class doesn't have a constructor that takes an initializer_list:
MyClass a { string() };
As it has already been pointed out by Seth, that is a problem with the language and how the expression is parsed. Basically when the compiler finds the expression MyClass a(string()) it interprets it as the declaration of a function a that has the signature MyClass (std::string (*)()) (The extra (*) comes from an implicit conversion from function to pointer to function in arguments).
There are different approaches to overcome that syntax in your particular case:
MyClass a(""); // 1
MyClass b = std::string(); // 2
MyClass c(( std::string() )); // 3
The first approach is not to use the T() expression to create the rvalue, but rather a constant literal that will produce the same output. The shortcoming of this approach is that in this particular case you can use a literal, but the same solution cannot be applied to other types (i.e. if you had your own type that only had a default constructor)
The second approach is avoiding direct initialization, as the alternative syntax cannot be parsed as a function declaration. The problem with this approach is that while the result in your particular case is the same, it requires the constructor not to be explicit. (I.e. it would fail if your constructor was declared explicit MyClass( std::string const & )), but it is none
The third approach is adding an extra set of parenthesis around the first argument to the constructor (note that the same problem in parsing would happen with MyClass a(std::string(), std::string())). The problem with this approach (opinion) is that it is ugly, but it is otherwise the most flexible of the three.
Can somebody tell me what precisely
operator std::string()
stands for?
It is a conversion operator that allows the object to be explicitly or implicitly casted to std::string. When such a cast occurs, the operator is invoked and the result of the cast is the result of the invocation.
As an example of an implicit cast, suppose you had a function that accepted type std::string or const std::string&, but not the given object type. Passing your object to that function would result in the conversion operator being invoked, with the result passed to the function instead of your type.
It is a cast operator. Any class that defines this type can be used anywhere a std::string is required. For instance,
class Foo {
public:
operator std::string() const { return "I am a foo!"; }
};
...
Foo foo;
std::cout << foo; // Will print "I am a foo!".
Cast operators are almost always a bad idea, since there is invariably a better way to achieve the same result. In the above case, you are better off defining operator<<(std::ostream&, const Foo&).