Passing a function object: Error - c++

What's wrong with the following little program that passes a function object?
#include <iostream>
#include <functional>
void foo(const std::unary_function<const std::string&, void>& fct) {
const std::string str = "test";
fct(str); // error
}
class MyFct : public std::unary_function<const std::string&, void> {
public:
void operator()(const std::string& str) const {
std::cout << str << std::endl;
}
};
int main(int argc, char** argv){
MyFct f;
foo(f);
return 0;
}
I'm getting the following error in line 6:
no match for call to
`(const std::unary_function<const std::string&, void>) (const std::string&)'

A common mistake. unary_function and binary_function are just two structs that add typedefs
argument_type
result_type
and respectively
first_argument_type
second_argument_type
result_type
Not more. They are for convenience of creators of function object types, so they don't have to do those themselves. But they don't behave polymorphic. What you want is function object wrapper. boost::function comes to mind:
void foo(boost::function<void(const std::string&)> const& fct) {
const std::string str = "test";
fct(str); // no error anymore
}
Or make it a template
template<typename FunctionObject>
void foo(FunctionObject const& fct) {
const std::string str = "test";
fct(str); // no error anymore
}
You can take it by value and then return the copy from foo if use it to apply it to some sequence. Which would allow the function object to update some state variables among its members. for_each is an example that does it like that. Generally, anyway, i would accept them by value because they are usually small and copying them allows greater flexibility. So i do
template<typename FunctionObject>
void foo(FunctionObject fct) {
const std::string str = "test";
fct(str); // no error anymore
}
You will then be able to take a copy of fct and save it somewhere, and fct's operator() can be non-const and update some members (which is part of the whole point of operator()). Remember if you take a function object by const reference, you can't generally copy it, because the user could have passed a function. Copying it then will try to locally declare a function instead of a local function pointer. However, accepting by-value will accept a function pointer instead when a function was passed, which can safely be copied.

Related

How to pass std::function as an argument to a mocked method in gmock?

I am getting a runtime error when trying to pass an std:function as an argument to a mocked method inside EXPECT_CALL.
I wish to verify that Bar is called with callback as an argument.
Code:
#include <gtest/gtest.h>
#include <gmock/gmock.h>
class Foo {
public:
virtual void Bar(const std::function<void (const std::string &name)> &callback) = 0;
};
class MockFoo : public Foo {
public:
MOCK_METHOD(void, Bar, (const std::function<void (const std::string &name)> &callback));
};
TEST(FooBarTest, callback) {
MockFoo foo;
const std::function<void(const std::string &name)> callback;
EXPECT_CALL(foo, Bar(callback)).Times(1);
foo.Bar(callback);
}
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
An error is produced at runtime:
/usr/local/include/gtest/gtest-matchers.h:211:60: error: no match for ‘operator==’ (operand types are ‘const std::function<void(const std::__cxx11::basic_string<char>&)>’ and ‘const std::function<void(const std::__cxx11::basic_string<char>&)>’)
bool operator()(const A& a, const B& b) const { return a == b; }
There are pre-defined ACTIONS that you could use for this purpose. Your EXPECT_CALL would look something like:
using namespace testing; // for brevity
TEST(FooBarTest, callback) {
MockFoo foo;
const std::function<void(const std::string &name)> callback;
EXPECT_CALL(foo, Bar(_)).WillOnce(Invoke(callback));
foo.Bar(callback);
}
As pointed out by #IanGralinski, there's no matcher for std::function, so you can use any matcher for the call (i.e. _).
However, this is not how I would use gmock here - why mocking Foo if you use it directly? Usually mocks are used when you test interactions of your (real) class with other classes (mocked). So in your example: Foo could be mocked by MockFoo and used by some other class (real one), using dependency injection.
On a side note, remember to add virtual destructor to Foo if the object derived from Foo is to be deleted by pointer to Foo (this would be UB without virtual dtor).
The arguments to the method named in an EXPECT_CALL are actually matchers. When you just provide a value (something which is not already a gmock Matcher<T> type), that implies an Eq matcher. So EXPECT_CALL(foo, Bar(callback)) really means EXPECT_CALL(foo, Bar(Eq(callback))). The trouble is, std::function does not provide an operator== for comparing two functions. Its type-erasure properties mean an equality test would be impossible to implement in general, plus of course some of the class functor types it might wrap around won't have their own operator== either.
But it is possible to test whether a std::function contains a very specific object. If you don't want to just ignore the argument by expecting Bar(_), here's an idea for identifying whether a std::function is a specific dummy function.
First, create a callable class which we'll use to initialize the std::function object. I'll also have its operator() call a mock method, which is not needed when it's just passed to a mock function, but this will make it possible to use the same std::function in different contexts, or set expectations before one real function which will both call it directly and pass it to a mocked interface.
template <typename FuncT> class DummyFunction; // undefined
template <typename RetType, typename... ArgTypes>
class DummyFunction<RetType(ArgTypes...)> {
public:
constexpr DummyFunction() : DummyFunction(0) {}
explicit constexpr DummyFunction(int key) : m_key(key) {}
constexpr DummyFunction(const DummyFunction& f) : m_key(f.m_key) {}
constexpr int key() const { return m_key; }
MOCK_METHOD(RetType, doCall, (ArgTypes...));
RetType operator()(ArgTypes... args)
{ return doCall(std::forward<ArgTypes>(args)...); }
friend constexpr bool operator==(const DummyFunction& f1, const DummyFunction& f2)
{ return f1.m_key == f2.m_key; }
friend constexpr bool operator!=(const DummyFunction& f1, const DummyFunction& f2)
{ return !(f1 == f2); }
friend std::ostream& operator<<(std::ostream& os, const DummyFunction& f)
{ return os << "DummyFunction(" << f.m_key << ")"; }
private:
int m_key;
};
Then a gmock Matcher to test whether a std::function contains a DummyFunction object with the exact same function type as template parameter and the same key as a given DummyFunction object could look like this. Since it's possible to convert one type of std::function to another as long as the parameter types and return types convert correctly (or the return type changes to void), I made it a "polymorphic" matcher which accepts any std::function specialization for testing.
template <class DummyFuncType>
class IsDummyFunctionTester {
public:
explicit constexpr IsDummyFunctionTester(int key) : m_key(key) {}
// The three member functions required for gmock "PolymorphicMatcher":
template <typename FuncType>
bool MatchAndExplain(const std::function<FuncType>& f,
::testing::MatchResultListener* listener) const {
bool type_ok = f.target_type() == typeid(DummyFuncType);
if (type_ok) {
int f_key = f.template target<DummyFuncType>()->key();
if (f_key == m_key) return true;
*listener << "std::function contains DummyFunction(" << m_key << ")";
} else if (!f) {
*listener << "std::function is empty";
} else {
// Note name() is implementation dependent. For g++/clang it's mangled.
*listener << "std::function target's type_info::name() is "
<< f.target_type().name();
}
return false;
}
void DescribeTo(std::ostream* os) const
{ *os << "is a DummyFunction(" << m_key << ")"; }
void DescribeNegationTo(std::ostream* os) const
{ *os << "is not a DummyFunction(" << m_key << ")"; }
private:
int m_key;
};
template <typename FuncType>
decltype(auto) StdFuncIsDummyFunc(const DummyFunction<FuncType>& f) {
return ::testing::MakePolymorphicMatcher(
IsDummyFunctionTester<DummyFunction<FuncType>>(f.key()));
}
So finally, you can do:
TEST(FooBarTest, callback) {
MockFoo foo;
const DummyFunction<void(const std::string &name)> callback;
EXPECT_CALL(foo, Bar(StdFuncIsDummyFunc(callback))).Times(1);
foo.Bar(callback);
}
If you have just one DummyFunction, or if exactly which DummyFunction is which isn't important for the test, you can just use the default "key" of zero like above. Otherwise, you can specify unique keys for each distinct dummy callback.

Why is const in component function in class necessary [duplicate]

What is the meaning of const in declarations like these? The const confuses me.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
When you add the const keyword to a method the this pointer will essentially become a pointer to const object, and you cannot therefore change any member data. (Unless you use mutable, more on that later).
The const keyword is part of the functions signature which means that you can implement two similar methods, one which is called when the object is const, and one that isn't.
#include <iostream>
class MyClass
{
private:
int counter;
public:
void Foo()
{
std::cout << "Foo" << std::endl;
}
void Foo() const
{
std::cout << "Foo const" << std::endl;
}
};
int main()
{
MyClass cc;
const MyClass& ccc = cc;
cc.Foo();
ccc.Foo();
}
This will output
Foo
Foo const
In the non-const method you can change the instance members, which you cannot do in the const version. If you change the method declaration in the above example to the code below you will get some errors.
void Foo()
{
counter++; //this works
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; //this will not compile
std::cout << "Foo const" << std::endl;
}
This is not completely true, because you can mark a member as mutable and a const method can then change it. It's mostly used for internal counters and stuff. The solution for that would be the below code.
#include <iostream>
class MyClass
{
private:
mutable int counter;
public:
MyClass() : counter(0) {}
void Foo()
{
counter++;
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; // This works because counter is `mutable`
std::cout << "Foo const" << std::endl;
}
int GetInvocations() const
{
return counter;
}
};
int main(void)
{
MyClass cc;
const MyClass& ccc = cc;
cc.Foo();
ccc.Foo();
std::cout << "Foo has been invoked " << ccc.GetInvocations() << " times" << std::endl;
}
which would output
Foo
Foo const
Foo has been invoked 2 times
The const means that the method promises not to alter any members of the class. You'd be able to execute the object's members that are so marked, even if the object itself were marked const:
const foobar fb;
fb.foo();
would be legal.
See How many and which are the uses of “const” in C++? for more information.
The const qualifier means that the methods can be called on any value of foobar. The difference comes when you consider calling a non-const method on a const object. Consider if your foobar type had the following extra method declaration:
class foobar {
...
const char* bar();
}
The method bar() is non-const and can only be accessed from non-const values.
void func1(const foobar& fb1, foobar& fb2) {
const char* v1 = fb1.bar(); // won't compile
const char* v2 = fb2.bar(); // works
}
The idea behind const though is to mark methods which will not alter the internal state of the class. This is a powerful concept but is not actually enforceable in C++. It's more of a promise than a guarantee. And one that is often broken and easily broken.
foobar& fbNonConst = const_cast<foobar&>(fb1);
These const mean that compiler will Error if the method 'with const' changes internal data.
class A
{
public:
A():member_()
{
}
int hashGetter() const
{
state_ = 1;
return member_;
}
int goodGetter() const
{
return member_;
}
int getter() const
{
//member_ = 2; // error
return member_;
}
int badGetter()
{
return member_;
}
private:
mutable int state_;
int member_;
};
The test
int main()
{
const A a1;
a1.badGetter(); // doesn't work
a1.goodGetter(); // works
a1.hashGetter(); // works
A a2;
a2.badGetter(); // works
a2.goodGetter(); // works
a2.hashGetter(); // works
}
Read this for more information
Blair's answer is on the mark.
However note that there is a mutable qualifier which may be added to a class's data members. Any member so marked can be modified in a const method without violating the const contract.
You might want to use this (for example) if you want an object to remember how many times a particular method is called, whilst not affecting the "logical" constness of that method.
Meaning of a Const Member Function in C++ Common Knowledge: Essential Intermediate Programming gives a clear explanation:
The type of the this pointer in a non-const member function of a class
X is X * const. That is, it’s a constant pointer to a non-constant X
(see Const Pointers and Pointers to Const [7, 21]). Because the object
to which this refers is not const, it can be modified. The type of
this in a const member function of a class X is const X * const. That
is, it’s a constant pointer to a constant X. Because the object to
which this refers is const, it cannot be modified. That’s the
difference between const and non-const member functions.
So in your code:
class foobar
{
public:
operator int () const;
const char* foo() const;
};
You can think it as this:
class foobar
{
public:
operator int (const foobar * const this) const;
const char* foo(const foobar * const this) const;
};
I would like to add the following point.
You can also make it a const & and const &&
So,
struct s{
void val1() const {
// *this is const here. Hence this function cannot modify any member of *this
}
void val2() const & {
// *this is const& here
}
void val3() const && {
// The object calling this function should be const rvalue only.
}
void val4() && {
// The object calling this function should be rvalue reference only.
}
};
int main(){
s a;
a.val1(); //okay
a.val2(); //okay
// a.val3() not okay, a is not rvalue will be okay if called like
std::move(a).val3(); // okay, move makes it a rvalue
}
Feel free to improve the answer. I am no expert
when you use const in the method signature (like your said: const char* foo() const;) you are telling the compiler that memory pointed to by this can't be changed by this method (which is foo here).
Here const means that at that function any variable's value can not change
class Test{
private:
int a;
public:
void test()const{
a = 10;
}
};
And like this example, if you try to change the value of a variable in the test function you will get an error.
The const keyword used with the function declaration specifies that it is a const member function and it will not be able to change the data members of the object.
https://isocpp.org/wiki/faq/const-correctness#const-member-fns
What is a "const member function"?
A member function that inspects (rather than mutates) its object.
A const member function is indicated by a const suffix just after the member function’s parameter list. Member functions with a const suffix are called “const member functions” or “inspectors.” Member functions without a const suffix are called “non-const member functions” or “mutators.”
class Fred {
public:
void inspect() const; // This member promises NOT to change *this
void mutate(); // This member function might change *this
};
void userCode(Fred& changeable, const Fred& unchangeable)
{
changeable.inspect(); // Okay: doesn't change a changeable object
changeable.mutate(); // Okay: changes a changeable object
unchangeable.inspect(); // Okay: doesn't change an unchangeable object
unchangeable.mutate(); // ERROR: attempt to change unchangeable object
}
The attempt to call unchangeable.mutate() is an error caught at compile time. There is no runtime space or speed penalty for const, and you don’t need to write test-cases to check it at runtime.
The trailing const on inspect() member function should be used to mean the method won’t change the object’s abstract (client-visible) state. That is slightly different from saying the method won’t change the “raw bits” of the object’s struct. C++ compilers aren’t allowed to take the “bitwise” interpretation unless they can solve the aliasing problem, which normally can’t be solved (i.e., a non-const alias could exist which could modify the state of the object). Another (important) insight from this aliasing issue: pointing at an object with a pointer-to-const doesn’t guarantee that the object won’t change; it merely promises that the object won’t change via that pointer.
In const objects only const methods can be called. All fielnd in such a method considered as const field.
Last issue has curious effect:
pointer becomes a const pointer int* const, which is not the same as a pointer to const const int*. Thus you can alter the object which pointer points to, but can't make pointer to point to another object.
reference should become a const reference, but it is invariantly a const reference: you can not re-init it to another object. But again you can alter the object which reference refers to.

Constructor for `const` object

Consider this code:
#include <iostream>
class test
{
public:
test( char *arg )
: _arg( arg )
{}
char *_arg;
};
int main( )
{
char *txt1 = "Text one"; // Ignore this warning.
const char *txt2 = "Text two";
test t1( txt1 ); // Normal case, nothing new.
const test t2( txt2 ); // Since object is const, I'd like to be able to pass a const argument in.
}
It blows up with the error:
error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
const test t2( txt2 );
Then I tried to add a second constructor to test whether the compiler could select the right one for t2, my const object:
test( const char *arg )
: _arg( arg )
{}
but then the error is:
error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
: _arg( arg )
So declaring my object as const does not make its fields const as well.
How to properly declare my class constructors so that it can handle const and non-const object creation?
How to properly declare my class constructors so that it can handle const and non-const object creation?
The object isn't const during construction, or the constructor wouldn't be able to initialize the object (since all data members would be const).
So, constructors can't be const-qualified and you can't have a constructor overload used for const objects.
Now, you can overload on the argument, but your data member always has type char * during construction, although it's qualified to char * const (not const char *) when used in a const-qualified instance of test.
Options are:
overload constructor on argument type, and store a char * always. If you're passed a const char * you have to copy it (and you're responsible for knowing that you own and must deallocate this memory)
In this scheme, you rely on keeping the pointer private and using const-qualified accessors to stop the contents of the pointer being changed via a const-qualified object.
Again, you need to do this manually because char * const is a different type than const char *, because constness of the pointed-to type isn't related to constness of the pointer: having a const instance of your class just stops you mutating the pointer, not the characters it points to.
overload constructor and store a const char * always. This avoids copying but obviously doesn't work if you sometimes need to change the pointed-to characters
just write different mutable-string and immutable-string classes
If it helps, consider this:
template <typename T> struct test {
T* p_;
test(T *p) : p_(p) {}
};
template <typename T> test<T> mktest(T *p) { return {p}; }
and note that
const char *ccp = "immutable characters in a string literal";
char *cp = strdup(ccp);
auto a = mktest(ccp);
auto b = mktest(cp);
gives a the type test<const char>, and b the type test<char> and that these types are not the same, are not convertible, and are no more closely related in the language than to test<T> for any other type T.
A note: this is a long answer for a use case that might be a bad design. Yet, the reason and the main focus for the long answer is:
to show and explain what is not possible
to present a way in which one can make the compiler decide based on the constness of a parameter whether to create a holding const object and to preserve this information even if the object is passed on. Which is very close to the OP request.
As explained in other answers, you can have two constructors, one for const parameter and the other for non-const, but both constructors would just create an object that can be either const or non-const. So this doesn't help.
Another approach could be to have a factory method that would create either a const object or a non-const, according to the constness of the parameter. Though this may sound promising it would not allow to preserve the semantics of the difference between the two, as shown in the following pseudo code:
// creating an object holding a const, using the factory method `create`:
const MyClass const_holder = create(const_param);
// however you cannot prevent this:
MyClass non_const_holder = create(const_param);
The factory would create in the second case above a const object that would be copied or moved (or just created directly as non_const_obj with copy elision, since C++17 as mandatory copy elision). You cannot do anything to avoid the second case unless you delete copy and move, in which case the first case wouldn't work also and the all thing collapses.
So, without creating actually two different types it is impossible to preserve the information of which constructor was used and to avoid assignment of an object created with const param into an object that doesn't.
However, there is no real need to bother the user with the fact that there are two classes, with a proper template implementation the user can have simple code that gives the feeling that there is only one class in the game, something like:
// creating a const holder with a factory method
// the type would *remember* that it is holding a const resource
// and can act accordingly
auto const_holder = create(const_param);
// and you can also create a non const holder with the same factory
auto non_const_holder = create(param);
These operations would be allowed:
// (a) calling a non const method on the content of the non const holder
non_const_holder->non_const_method();
// (b) assigning a non const holder into a const holder object
// -- same as assigning char* to const char*
const_holder = non_const_holder;
These operations would NOT be allowed:
// (a) calling a non const method on the content of a const holder
const_holder->non_const_method(); // should be compilation error
// (b) assigning a const holder into a non const holder object
// -- same as one cannot assign const char* to char*
non_const_holder = const_holder; // should be compilation error
In a way, this is very similar to the idea of propagate_const...
The code would have a factory method:
template<class T>
Pointer<T> create(T* t) {
return Pointer<T>::create(t);
}
And two implementations for the template class Pointer.
base template:
template<class T>
class Pointer {
T* ptr;
Pointer(T* p) : ptr(p) {}
friend class Pointer<const T>;
public:
// factory method
static Pointer create(T* p) {
return p;
}
operator T*() { return ptr; }
operator const T*() const { return ptr; }
};
and a specialized one for the const version:
template<class T>
class Pointer<const T> {
const T* ptr;
Pointer(const T* p) : ptr(p) {}
public:
Pointer(const Pointer<T>& other) {
ptr = other.ptr;
}
// factory method
static const Pointer create(const T* p) {
return p;
}
operator const T*() { return ptr; }
operator const T*() const { return ptr; }
};
The main would look like:
int main() {
char str[] = "hello";
const char* const_str = "hello";
// non-const - good!
auto s1 = create(str);
// const holding non-const - ok!
const auto s2 = create(str);
// non-const that holds const - good!
auto s3 = create(const_str);
// also possible: const holding const
const auto s4 = create(const_str);
s1[4] = '!'; // OK
// s2[0] = '#'; // obviously doesn't compile - s2 is const
// s3[0] = '#'; // doesn't compile - which is good - s3 holds const!
// s4[0] = 'E'; // obviously doesn't compile - s4 is const
// avoids assignment of s3 that holds a const into s1 that holds a non-const
// s1 = s3; // <= doesn't compile - good!
s3 = s1; // allows assignment of `holding-non-const` into `holding-const`
s3 = s2; // allows assignment of `holding-non-const` into `holding-const`
s3 = s4; // allows assignment of `holding-const` into `holding-const`
}
Code: http://coliru.stacked-crooked.com/a/4729be904215e4b2
The problem you experience goes a bit deeper. It's an indication of a design issue.
You would like to expose only part of the API. You say that for a const object you will call only const methods and for non-const you can do anything. But this is problematic.
Either you accept const object strip it from const qualifier, and won't call non-const methods by a silent contract. Or, you need to limit methods, which makes a different object - type-wise.
C# library does it by providing a limited interface which wraps around original object and exposes only const methods. Something like this:
#include <iostream>
using namespace std;
struct A {
void f1() const {cout << "foo\n"; }
void f2() {cout << "bar\n"; }
};
struct readonlyA {
readonlyA(const A& a) : _a(a) {};
void f1() const {_a.f1();};
private:
const A& _a;
};
int main() {
A a;
readonlyA roA(a);
a.f2();
roA.f1();
roA.f2(); // error
return 0;
}
It's basically a read-only proxy.
The compiler does not care about what you actually do with the object at runtime.
Const works because the compiler will forbid certain things at compile time that could potentially change the object. This might be over-restrictive in certain situations, as the compiler often does not have the full picture of what's going on in the program.
Take for example the invocation a non-const member function on a const object: Even if the member function does not actually change the object's state, the compiler will still forbid it because the non-const function could potentially change the object.
Similar in your example: Even though you don't change the member for that particular const instance of the class, there could be other non-const instances of the same class somewhere, which is why it will refuse construct any instance of the class from a const object.
If you want a class that is guaranteed to leave its members unchanged, that would be a different type:
class test
{
public:
test( char *arg )
: _arg( arg )
{}
char *_arg;
};
class immutable_test
{
public:
immutable_test(char const* arg)
:_arg(arg)
{}
char const* _arg;
};
int main( )
{
char *txt1 = "Text one"; // Ignore this warning.
const char *txt2 = "Text two";
test t1( txt1 );
immutable_test t2( txt2 );
}
It can't be done. Just because the object is const, it doesn't mean that it guarantees the char* won't be used to modify its value. The constructor can mutate the argument, and code outside the class can modify its content if it is exposed. Consider the following example.
struct Test {
char* buffer;
Test(char* buffer):
buffer(buffer)
{
buffer[0] = 'a';
}
char* get() const {
return buffer;
}
};
int main(int argc, char* argv[]) {
std::string s{ "sample text" };
const Test t(s.data());
t.get()[1] = 'b';
t.buffer[2] = 'c';
std::cout << s << '\n';
}
The above prints abcple text, even though t is const. Even though it never modifies its members, it does change the pointed-to string and it allows outside code to modify it, too. This is why const objects cannot accept const char* arguments to initialize their char* members.
The compiler is preventing you from carelessly discarding the constness...
class test
{
public:
test(const char *arg)
: _arg(arg)
{}
const char *_arg;
};
Interesting.
Look at the example below (object myclass2) to learn how a const object does not necessarily provide the protection that you need!
#include <iostream>
#include <cctype>
#include <cassert>
class MyClass
{
public:
MyClass(char * str1, size_t size1) : str{str1}, size{size1}
{
}
char * capitalizeFirstChar()
{
*str = std::toupper(*str);
return str;
}
char nthChar(size_t n) const
{
assert(n < size);
return str[n];
}
char * str;
size_t size;
};
int main()
{
{
static char str1[] = "abc";
MyClass myclass1(str1, sizeof(str1) / sizeof(*str1));
myclass1.capitalizeFirstChar();
std::cout << myclass1.nthChar(0) << std::endl;
}
std::cout << "----------------------" << std::endl;
{
static const char str2[] = "abc";
// UGLY!!! const_cast
const MyClass myclass2(const_cast<char *>(str2), sizeof(str2) / sizeof(*str2));
// myclass2.capitalizeFirstChar(); // commented: will not compile
std::cout << myclass2.nthChar(0) << std::endl;
char c = 'x';
// myclass2.str = &c; // commented: will not compile
// The const myclass2, does not
// allow modification of it's members
myclass2.str[0] = 'Z'; // WILL COMPILE (!!) and should cause a segfault
// The const myclass2, CANNOT PROTECT THE OBJECT POINTED TO by str
// Reason: the member in MyClass is
// char *str
// not
// const char *str
std::cout << myclass2.nthChar(0) << std::endl;
}
}
Ok, the str member issue is actually best solved, by just making the members private.
But what about that ugly const_cast?
One way of solving this is splitting into a Const baseclass, and deriving for non-const behaviour (working with const-casts). Like this perhaps:
#include <iostream>
#include <cctype>
#include <cassert>
class MyClassConst
{
public:
MyClassConst(const char * str1, size_t size1) : str{str1}, size{size1}
{
}
char nthChar(size_t n) const
{
assert(n < size);
return str[n];
}
const char * str;
size_t size;
};
class MyClass : public MyClassConst
{
public:
MyClass(char * str1, size_t size1) : MyClassConst{const_cast<const char *>(str1), size1}
{
}
char * capitalizeFirstChar()
{
char * cp = const_cast<char *>(str);
*cp = std::toupper(*cp);
return cp;
}
};
int main()
{
{
static char str1[] = "abc";
MyClass myclass1(str1, sizeof(str1) / sizeof(*str1));
myclass1.capitalizeFirstChar();
std::cout << myclass1.nthChar(0) << std::endl;
}
std::cout << "----------------------" << std::endl;
{
static const char str2[] = "abc";
// NICE: no more const_cast
const MyClassConst myclass2(str2, sizeof(str2) / sizeof(*str2));
// a.capitalizeFirstChar(); // commented: will not compile
std::cout << myclass2.nthChar(0) << std::endl;
char c = 'x';
// myclass2.str = &c; // commented: will not compile
// The const myclass2, does not
// allow modification of it's members
// myclass2.str[0] = 'Z'; // commented: will not compile
std::cout << myclass2.nthChar(0) << std::endl;
}
}
Is it worth it? Depends.
One is kindof trading the const-cast outside of the class... for const-cast inside the class. So maby for library code (including ugly internals, and static code analysis exceptions), with clean outside usage, it's a match...

C++ templated function wrapper arguments using const& versus &

Creating a wrapper function for a constructor such as the following compiles just fine:
#include <iostream>
template <typename T>
class wrapper
{
public:
template <typename A0>
T* operator () (const A0& a0) const
{
return new T(a0);
}
};
class Foo
{
public:
Foo(int i) { std::cout << "Foo:Foo(" << i << ")" << std::endl; }
};
int main(int argc, char** argv)
{
wrapper<Foo>()(42);
return 0;
}
But the code does not compile when I update the line:
T* operator () (const A0& a0) const
to:
T* operator () (A0& a0) const
My guess is this has to do with the rvalue '42' not being bindable to to a non-const reference. But when I make the reference const this will mean that I could never call a constructor that actually takes a non-const reference. Can someone explain what is going on here, and what is the right thing to do to make it work?
My guess is this has to do with the rvalue '42' not being bindable to to a non-const reference.
Yes. Correct.
But when I make the reference const this will mean that I could never call a constructor that actually takes a non-const reference.
No. Incorrect. You can still call it with non-const reference. In fact, that is how const-ness works : non-const reference/pointer/object can implicitly convert into const reference/pointer/object, but vice-versa is not true.
So try it out.

Overload a pointer to an overloaded function

If I try to define a pointer to an overloaded function
void myprint(int );
void myprint(const char* );
void (*funpointer)(int) = myprint;
the compiler understands that funpointer should point to the version of myprint that matches its arguments. Instead, I want funpointer to be overloaded as well.
I tried simply adding a couple lines like
void myprint(int );
void myprint(const char* );
void (*funpointer)(int);
void (*funpointer)(const char *);
void funpointer = myprint;
but then the compiler complains of conflicting declarations for funpointer (obviously).
Is there a way to achieve what I'm looking for? I would like the pointer to behave as an overloaded function. So I could call it as either funpointer(1) or funpointer("Hey.") and it would work as the respective version of myprint.
Why are you doing this? Function pointers are for runtime polymorphism based on application state. Plain old overloads work fine if, the only variance is the argument type.
If you want to be able to, say write a library that will call overloads defined later, in client code, do something like the following:
void foo(int x) { printf("int\n");}
void foo(const char* c){ printf("char*\n"); }
template <class T> void callfoo(T t) { foo(t); }
int main(int argc, char* argv[])
{
int x = 3;
callfoo(x);
const char* p = "Hello world";
callfoo(p);
return 0;
}
This allows the lib to call overloads for types it is not actually aware of until link time.
No can do. You can't have two variables in the same scope with the same name.
Pointer is a Type, it cannot be overloaded. Only functions can be overloaded.
There is no way to achieve overloading of a pointer in C++.
You can't do it with function pointers... the argument list is part of the type, so any given function pointer can only correspond to one specific overload at a time. You might be able to fake it with function objects, though, depending on what you need to do.
struct MyPrint {
void operator()(int i) { int_f(i); }
void operator()(const char* c_str) { str_f(c_str); }
std::function<void(int)> int_f;
std::function<void(const char*) str_f;
};
void print_int(int i) { cout << i << endl; }
void print_string(const char* str) { cout << str << endl; }
int main() {
MyPrint p;
p.int_f = print_int;
p.str_f = print_string;
p(5);
p("Hi");
}
You lose the ability to just overload by name; you can't add a set_functions(f) that takes a function name and extracts both versions of the function. But as I showed, now you aren't limited to functions with the same name, or even just to functions. The object is also bigger than it used to be, and likely involves some heap allocations.
This might be considered "clunky", but you could do something like the following:
template<typename T>
struct funcptr_struct
{
typedef T type;
static type ptr;
};
template<> funcptr_struct<void(*)(int)>::type funcptr_struct<void(*)(int)>::ptr = myprint;
template<> funcptr_struct<void(*)(const char*)>::type funcptr_struct<void(*)(const char*)>::ptr = myprint;
You can then call each version of the myprint function using syntax like the following:
funcptr_struct<void(*)(int)>::ptr(5);