As stated here std::string is not a template function but rather the standard choose to use function overloading to provide this function for different types. My question is why use overloading when template/specialisation seems to make more sense to me in this case? Consider that if the standard has defined something like this:
template <typename T>
std::string std::to_string(const T& v);
Then we can freely add specialisation for any type in our program to conform to this signature, thus C++ will have a uniform way to transform types into human-readable strings. Why not do this? What's the thinking behind the current design?
Edit 1:
The main critic I have for the current design is that adding an overload to std is not allowed so we can not write anything like std:to_string(object-that-is-of-user-defined-types) and has to fall back on defining a to_string() in their own namespace and remember where to use their version or the std version depends on the types they are dealing with... This sounds like a headache for me.
One thing I really liked about Python (or some other languages) is that you can make your own type work just like a native type by implementing some magic methods. I think what this question is fundamentally about is that why C++ decided to disallow people to implement std::to_string() for their own type and thus forbid us from conforming to the same interface everywhere.
For common things like hash or to_string(), isn't it better to have a single interface on language/stdlib level and then expect users to conform to that interface, rather than having multiple interfaces?
why C++ decided to disallow people to implement std::to_string for their own type
This is where ADL is useful. We already have the example of how to correctly do this with std::swap, which is successfully done in many codebases already:
template <typename T>
void swap_example(T & a, T & b) {
using std::swap;
swap(a, b);
}
This works if the namespace T is declared in has a compatible swap() function, without needing to overload std::swap. We can do the same thing with std::to_string:
template <typename T>
void to_string_example(T const & x) {
using std::to_string;
to_string(x);
}
This will likewise work if the namespace T is declared in has a to_string function that can accept a T const & argument. For example:
namespace example {
class Foo;
std::string to_string(Foo const &);
}
to_string_example(example::Foo{}) would find and use the corresponding example::to_string function.
remember where to use their version or the std version depends on the types they are dealing with... This sounds like a headache for me.
If this really is such a headache for you, you can hide the ADL behind a utility function in your project:
template <typename T>
std::string adl_to_string(T const & x) {
using std::to_string;
return to_string(x);
}
Now you can use adl_to_string(...) instead of std::to_string(...) everywhere and not have to think about it.
This may sound a bit boring, but the purpose of std::to_string is to format as if you had used sprintf and as sprintf supports only a limited set of types this is also true for std::to_string. There is no need to make it a template.
As explained in detail in this answer that design does not have the restriction you think it has. You can still supply your own foo::to_string(foo::bar&) and in code that uses proper qualification of the name to enable ADL your overload will be called. For this it is not necessary to add an overload to std.
Related
Sorry for the newbie question, but I have a feeling I am missing something here:
If I have a certain class template which looks like this (basically the only way to pass a lambda to a function in C++, unless I am mistaken):
template<typename V, typename F>
class Something
{
public:
int some_method(V val, F func) {
double intermediate = val.do_something();
return func(intermediate);
}
}
By reading the implementation of this class, I can see that the V class must implement double do_something(), and that F must be a function/functor with the signature int F(double).
However, in languages like Java or C#, the constraints for the generic parameters are explicitly stated in the generic class signature, so they are obvious without having to look at the source code, e.g.
class Something<V> where V : IDoesSomething // interface with the DoSomething() method
{
// func delegate signature is explicit
public int SomeMethod(V val, Func<double, int> func)
{
double intermediate = val.DoSomething();
return func(intermediate);
}
}
My question is: how do I know how to implement more complex input arguments in practice? Can this somehow be documented using code only, when writing a library with template classes in C++, or is the only way to parse the code manually and look for parameter usage?
(or third possibility, add methods to the class until the compiler stops failing)
C# and Java Generics have similar syntax and some common uses with C++ templates, but they are very different beasts.
Here is a good overview.
In C++, by default template checking was done by instantiation of code, and requrements are in documentation.
Note that much of the requirements of C++ templates is semantic not syntactic; iterators need not only have the proper operations, those operations need to have the proper meaning.
You can check syntactic properties of types in C++ templates. Off the top of my head, there are 6 basic ways.
You can have a traits class requirement, like std::iterator_traits.
You can do SFINAE, an accidentally Turing-complete template metaprogramming technique.
You can use concepts and/or requires clauses if your compiler is modern enough.
You can generate static_asserts to check properties
You can use traits ADL functions, like begin.
You can just duck type, and use it as if it had the properties you want. If it quacks like a duck, it is a duck.
All of these have pluses and minuses.
The downside to all of them is that they can be harder to set up than "this parameter must inherit from the type Foo". Concepts can handle that, only a bit more verbose than Java.
Java style type erasure can be dominated using C++ templates. std::function is an example of a duck typed type eraser that allows unrelated types to be stored as values; doing something as restricted as Java is rarely worthwhile, as the machinery to do it is harder than making something more powerful.
C# reification cannot be fully duplicated by C++, because C#'s runtime environment ships with a compiler, and can effectively compile a new type when you instantiate at runtime. I have seen people ship compilers with C++ programs, compile dynamic libraries, then load and execute them, but that isn't something I'd advise.
Using modern c++20, you can:
template<Number N>
struct Polynomial;
where Number is a concept which checks N (a type) against its properties. This is a bit like the Java signature stuff on steroids.
And by c++23 you'll be able to use compile time reflection to do things that make templates look like preprocessor macros.
Does C++ have a standard way which do the same things as std::__and_ and std::__or_ do? I always using them in my private project, but now I'm writing a public project, and these template helper seems not part of the C++ STL API, so is there a standard way? The worst case I can see is to copy the std::__and_ from the header to my project, but I think this is not very elegant.
An example:
// if a type is a pointer or a reference, do some thing.
template<typename T>
std::enable_if_t<std::__or_<std::is_pointer<T>, std::is_reference<T>>::type>
DoSomething(T t) {
// do something
}
If you are meaning, by that, a structure/constexpr boolean that ands the template parameters, then it would seems like std::conjunction and std::disjunction are the C++17 structs you want (note that the values are accessible directly with the _vs ones).
They are in the type_traits header.
In contrast with other languages, C++ classes cannot be extended once defined.
This is why free functions are preferable to member functions because these are more general way to extend the behavior of a class.
At the same time, the dot syntax (only used for member functions) can have some notational advantage, for example when there is an object that is "more important" than the rest of the arguments in a function call.
For example,
allocator a;
a.allocate(n); // vs. allocate(a, n);
This creates a tension in the language.
(A tension that in early C++ contributed to the creation of bloated classes.)
In the best case, the difference is syntactic.
In the worst case the desired syntax using dot forces the methods to be defined inside the class (with the risk of making the class to large by including a lot of member functions).
This is what C++ is so far, and we are used to live with this.
However there is, for some cases a loop hole.
The question is whether this loop hole is frequently exploited or if it can create problems down the road.
The fact is that one can emulate extensions of a class by leaving template member function open.
For example:
struct A{
void f(int n) const{...}
void g(std::string s) const{...};
};
The "member" g cannot be extended to make this work A a; a.g(42).
However one can do this to make the syntax work:
struct A{
void f(int n) const{}
template<class T> void g(T t) const; // this can be even customized by a user of the library
};
// this can be defined anywhere down the road (but before `A::g<T>` is instantiated I think).
template<> void A::g<int>(int t) const{}
template<> void A::g<std::string>(std::string t) const{}
The extension is not general, any extension will have to have a fixed name (and one parameter) in this case but it feels like an extension nevertheless.
Besides the ugly out of class template code, is there any problem in using this technique to extend classes?
It is not straightforward in the general case but the technique can be even extended to customize different return types I think (here I used void for simplicity, another simple cases is when the return type is T itself also).
A problem I can see is that partial specialization is probably very difficult.
Another one is that order of instantiation can be problematic, the customizations need to be defined before first use (?).
Customizing a named function is not very impressive.
But other functions like template<class T> operator=(T const); can be customized. Effectively, this is like overloading assignment from outside the class which is not possible by normal means.
Besides the ugly out of class template code, is there any problem in using this technique to extend classes?
No, it is called "member templates" and it is a perfectly valid thing in C++.
Update:
I know it is valid. I am wondering if this is a technique frequently used.
I've personally never used it that often. Usually, have been deciding to implement the whole class as a template rather than focusing on individual functions. Yet at the same time I believe this sort of things depend on what you are trying to achieve and what is your personal taste. I mean it is a feature of the language and so why not use it whenever it feels like it would suit.
I have been writing in c++ for a few months, and i am comfortable enough with it now to begin implementing my own library, consisting of things that i have found myself reusing again and again. One thing that nagged me was the fact that you always had to provide a beginning and end iterator for functions like std::accumulate,std::fill etc...
The option to provide a qualified container was completely absent and it was simply an annoyance to write begin and end over and over. So, I decided to add this functionality to my library, but i came across problem, i couldn't figure out the best approach of doing so. Here were my general solutions:
1. Macros
- A macro that encapsulates an entire function call
ex. QUICK_STL(FCall)
- A macro that takes the container, function name, and optional args
ex. QUICK_STL(C,F,Args...)
2. Wrapper Function/Functor
- A class that takes the container, function name, and optional args
ex. quick_stl(F, C, Args...)
3. Overload Functions
- Overload every function in namespace std OR my library namespace
ex
namespace std { // or my library root namespace 'cherry'
template <typename C, typename T>
decltype(auto) count(const C& container, const T& value);
}
I usually steer clear of macros, but in this case it could certainty save alot
of lines of code from being written. With regards to function overloading, every single function that i want to use i must overload, which wouldn't really scale. The upside to that approach though is that you retain the names of the functions. With perfect forwarding and decltype(auto) overloading becomes alot easier, but still will take time to implement, and would have to be modified if ever another function was added. As to whether or not i should overload the std namespace i am rather skeptical on whether or not it would be appropriate in this case.
What would be the most appropriate way of going about overloading functions in the STD namespace (note these functions will only serve as proxy's to the original functions)?
You need to read this: Why do all functions take only ranges, not containers?
And This: STL algorithms: Why no additional interface for containers (additional to iterator pairs)?
I have been writing in c++ for a few months, and i am comfortable
enough with it now to begin implementing my own library...
Let me look on the brighter side and just say... Some of us have been there before.... :-)
One thing that nagged me was the fact that you always had to provide a
beginning and end iterator for functions like
std::accumulate,std::fill etc...
That's why you have Boost.Ranges and the Eric's proposed ranges that seems like it isn't gonna make it to C++17.
Macros
See Macros
Wrapper Function/Functor
Not too bad...Provided you do it correctly, You can do that, that's what essentially Ranges do for Containers... See the aforementioned implementations
Overload Functions
Overload every function in namespace std ...
Don't do that... The C++ standard doesn't like it.
See what the standard has to say
$17.6.4.2.1 The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within
namespace std unless otherwise specified. A program may add a template
specialization for any standard library template to namespace std only
if the declaration depends on a user-defined type and the
specialization meets the standard library requirements for the
original template and is not explicitly prohibited.
I have a simple template struct associating a string with a value
template<typename T> struct Field
{
std::string name; T self;
}
I have a function that I want to accept 1-or-more Fields of any type, and the Fields may be of possible different types, so I'm using a std::initializer_list because C++, to my knowledge, lacks typed variadic arguments, cannot determine the size of variadic arguments, and must have at least one other argument to determine where to start.
The problem is that I don't know how to tell it to accept Fields that may be of different types. In Java, I would just use foo(Field<?> bar, Field<?>... baz), but C++ lacks both typed variadic arguments and wildcards. My only other idea is to make the parameter of type
std::initializer_list<Field<void*>>, but that seems like a bad solution... Is there a better way to do it?
A couple of things...
C++11 (which you seem to have since you are talking about std::initializer_list) does have typed variadic arguments, in particular they are named variadic templates
Java generics and C++ templates are completely different beasts. Java generics create a single type that stores a reference to Object and provides automatic casting in and out to the types in the interface, but the important bit is that it performs type erasure.
I would recommend that you explain the problem you want to solve and get suggestions for solutions to your problem that are idiomatic in C++. If you want to really mimic the behavior in Java (which, I cannot insist enough is a different language and has different idioms) you can use type erasure in C++ manually (i.e. use boost::any). But I have very rarely feel the need for full type erasure in a program... using a variant type (boost::variant) is a bit more common.
If your compiler has support for variadic templates (not all compilers do), you can always play with that, but stashing the fields for later in a vector may be a bit complicated for a fully generic approach unless you use type erasure. (Again, what is the problem to solve? There might be simpler solutions...)
Java generics are closer to just stuffing a boost::any into the self variable than to C++ templates. Give that a try. C++ templates create types that have no runtime or dynamic relarionship to each other by default.
You can introduce such a relationship manually, say via a common parent and type erasure and judicious use of pImpl and smart pointers.
C type variardic arguments are out of style in C++11. Variardic template arguments are very type safe, so long as your compiler has support for them (Nov 2012 CTP for MSVC 2012 has support for them (not update 1, the CTP), as does clang, and non-ancient versions of gcc).
Templates in C++ is a kind of metaprogramming, closer to writing a program that writes a program than it is to Java Generics. A Java Generic has one shared "binary" implementation, while each instance of a C++ template is a completely different "program" (which, via procedures like COMDAT folding, can be reduced to one binary implementation), whose details are described by the template code.
template<typename T>
struct Field {
T data;
};
is a little program that says "here is how to create Field types". When you pass in an int and double, the compiler does something roughly like this:
struct Field__int__ {
int data;
};
struct Field__double__ {
double data;
};
and you wouldn't expect these two types to be convertible between.
Java generics, on the other hand, create something like this:
struct Field {
boost::any __data__;
template<typename T>
T __get_data() {
__data__.get<T>();
}
template<typename T>
void __set_data(T& t) {
__data__.set(t);
}
property data; // reading uses __get_data(), writing uses __set_data()
};
where boost::any is a container that can hold an instance of any type, and access to the data field redirects through those accessors.
C++ provides means to write something equivalent to Java generics using template metaprogramming. To write something like C++ templates in Java, you'd have to have your Java program output custom Java byte or source code, then run that code in a way that allows a debugger to connect back to the code that writes the code as the source of the bugs.
There is no need to use wildcards in C++ templates, since in C++ it always knows the type, and is not "erased" like in Java. To write void foo(Field<?> bar, Field<?>... baz) method(or function) in C++, you would write:
template<class T, class... Ts>
void foo(Field<T> bar, Field<Ts>... baz);
Each Field<Ts> can be a different type. To use the variadic parameters inside the function, you just use baz.... So say you want to call another function:
template<class T, class... Ts>
void foo(Field<T> bar, Field<Ts>... baz)
{
foo2(baz...);
}
You can also expand the type with Field<Ts>..., so if you want to put it in a tuple(you can't put them in array since they can be different types):
template<class T, class... Ts>
void foo(Field<T> bar, Field<Ts>... baz)
{
std::tuple<Field<Ts>...> data(baz...);
}
This is not very idiomatic for C++. It can be done, perhaps; Coplien's book might have some ideas. But C++ is strongly typed because it believes in typing; trying to turn it into Smalltalk or fold it like a pheasant may lead to tears.