Say we have a class that can write stuff to output
class Writer
{
public:
int write(const std::string& str);
int write(const char* str, int len);
//...
};
I was fine with this, its flexible and all that, until I realized
char* buf = new char[n]; //not terminated with '\0'
//load up buf
Writer w;
w.write(buf); //compiles!
That is a really nasty bug.
We can amend somewhat with some templating
class WriterV2
{
public:
int write(const std::string& str);
int write(const char* str, int len);
template<typename... Args>
int write(const char*, Args...)
{ static_assert(sizeof...(Args) < 0, "Incorrect arguments"); }
//...
};
But this method has its problems
WriterV2 w;
w.write("The templating genius!"); //compile error
What do I do? What is a better design?
And before anyone asks, overloading for const char (&)[N]
does not work. It might be feasible to create a wrapper to do this, but that seems... overkill?
EDIT Adding a method write(char*)
and emitting an error there is not ideal. When passing buf
around through functions and all that, it might become const char*
.
In function overloading function has same name but accessing depends on the no. And type of arguments so, answer is option A & B. Overloading is nothing but same function with different arguments.
The correct answer is option4. Key Points Both functions and operators can be overloaded. C++ allows you to specify more than one definition for a function name or an operator in the same scope, which is called function overloading and operator overloading respectively. Hence the correct answer is function.
C++ lets you specify more than one function of the same name in the same scope. These functions are called overloaded functions, or overloads. Overloaded functions enable you to supply different semantics for a function, depending on the types and number of its arguments.
Operator overloading is a technique by which operators used in a programming language are implemented in user-defined types with customized logic that is based on the types of arguments passed.
ICS (Implicit Conversion Sequences) during overload resolution in C++ can produce surprising results as you've noticed, and also quite annoying..
You can provide necessary interfaces you need, then carefully employ templates to handle the string literal vs const char*
fiasco by taking advantage of partial ordering to delete
the unwanted overload.
Code:
#include <iostream>
#include <string>
#include <type_traits>
class Writer
{
public:
int write(std::string&&) { std::cout << "int write(std::string)\n"; return 0; }
int write(const std::string&) { std::cout << "int write(const std::string& str)\n"; return 0; }
int write(const char*, int){ std::cout << "int write(const char* str, int len)\n"; return 0; }
template<std::size_t N = 0, typename = std::enable_if_t<(N > 0)> >
int write(const char (&)[N]) { std::cout << "int write(string-literal) " << N << " \n"; return 0; }
template<typename T>
int write(T&&) = delete;
};
int main(){
char* buf = new char[30];
const char* cbuf = buf;
Writer w;
//w.write(buf); //Fails!
//w.write(cbuf); //Fails!
w.write(buf, 30); //Ok! int write(const char*, int);
w.write(std::string("Haha")); //Ok! int write(std::string&&);
w.write("This is cool"); //Ok! int write(const char (&)[13]);
}
Prints:
int write(const char* str, int len)
int write(std::string)
int write(string-literal) 13
Demo
Note that the solution above inherits a disadvantage of "overloading a function with an unconstrained Forwarding Reference". This means that all ICS to the argument type(s) of the viable functions in the overload set will be "deleted"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With