Compile-time detection of missing user-defined to_string() - c++

I want to provide a to_string(obj) function for every object type I create.
I found this question, applied the accepted answer, and it works. So far so good.
Then I created a new type, but forgot to write a to_string() for it (or better: I accidentally made it unreachable by ADL). The problem is: my program still compiles fine, and at runtime I get an obscure stack overflow(TM).
Is there a way to obtain a reasonable error message, instead?
Here is a small program to demonstrate the problem: an infinite recursion between notstd::to_string() and notstd::adl_helper::as_string().
#include <iostream>
#include <string>
namespace notstd {
namespace adl_helper {
using std::to_string;
template<class T>
std::string as_string( T&& t ) {
return to_string( std::forward<T>(t) );
}
}
template<class T>
std::string to_string( T&& t ) {
std::cout << "called" << std::endl; // <-- this is to show what's going on
return adl_helper::as_string(std::forward<T>(t));
}
class A {
/* both versions are needed, or the perfect forwarding candidate will
* always be chosen by the compiler in case of a non-perfect match */
//friend std::string to_string(A &a) { return std::string("a"); }
//friend std::string to_string(const A &a) { return std::string("a"); }
};
}
int main(int argc, char** argv) {
notstd::A a;
std::cout << to_string(a) << std::endl;
}
I tried creating a wrapper function that accepts one more parameter, to be used to perform the an anti-recursion check, like this:
#include <iostream>
#include <string>
#include <cassert>
namespace notstd {
namespace wrap_std {
std::string to_string(double v, bool) { return std::to_string(v); }
/* .... etc..... */
}
namespace adl_helper {
using wrap_std::to_string;
template<class T>
std::string as_string( T&& t ) {
return to_string( std::forward<T>(t), true );
}
}
template<class T>
std::string to_string( T&& t, bool recurring = false ) {
std::cout << "called" << std::endl;
assert(!recurring);
return adl_helper::as_string(std::forward<T>(t));
}
class A {
/* both versions are needed, or the perfect forwarding candidate will
* always be chosen by the compiler in case of a non-perfect match */
//friend std::string to_string(A &a) { return std::string("A"); }
//friend std::string to_string(const A &a) { return std::string("A"); }
};
}
int main(int argc, char** argv) {
notstd::A a;
std::cout << to_string(a) << std::endl;
}
The problems here are:
I'd have to wrap all std::to_string() overloads
I'll only get a runtime error, but I feel the problem could and should be detected ad compile time
I'm probably adding some overhead, for something useful only during development: maybe I could add some macros to deactivate all this in release mode, but it would add even more work
Maybe I could use a template to wrap std::to_string() and create specializations for my types... this would be a quite different beast, but at least it would provide a compile time error if a suitable specialization is not available. I would have, again, to wrap all std::to_string() overloads, and I'd probably have to (almost) forget about ADL, at least until c++20 is supported by all compilers, If I understand well.
Does anyone have a better solution?
Thanks!

The idea of that accepted answer is different: you put A outside notstd namespace and then use qualified notstd::to_string instead of unqualified to_string. That is:
namespace notstd {
// ...
}
class A {
friend std::string to_string(const A&);
};
A a;
std::cout << notstd::to_string(a);
Now your code won't compile if there is no friend function. Moreover, you need only one friend function (taking const A&), because notstd::to_string(T&&) won't be present in the overload set inside adl_helper::as_string(T&&).
Putting A inside notstd screws everything up. You have infinite recursion problem and you need two friends to handle both A and const A cases in the presence of notstd::to_string(T&&) candidate: if only one friend is defined, that candidate is a better match in one of the cases because const qualifier should be added/dropped to invoke the friend function.

Related

how to return an reference to an 'empty' object

The problem I tried to tackle today is the one where you want to return a reference, but you actually can't because in some specific case you return something 'empty'. Just to clarify, something like this:
std::array<std::string, 5> cStrings /* do something to init */
const std::string& get_my_string(/* args */) {
if(i_know_what_to_return()) {
/*
* returning happily something in
* cStrings if I know what
*/
} else {
/* oeps... i need to return something, I don't have :-( */
return std::string(); // DON'T TRY THIS AT HOME!
}
}
I was wondering if there is not a generic approach to avoid the creation of empty objects all over the place, or, even worse, start returning copies of the objects. So I was wondering if I could not create some sort of template class that allows me to tell the compiler to manage this for me. This was my approach (although its only one of many, all with a small variation in the template declaration since this produces an error)
template<typename T, decltype(T) V>
struct empty_reference {
using type = T;
static const T static_object_;
operator T&() const {
return static_object_;
}
};
template<typename T, decltype(T) V>
const typename empty_reference<T, V>::type
empty_reference<T, V>::static_object_ = V;
unfortunately, this does not work (I get an error on 'decltype(T) V' saying 'decltype expects an expression not a type'), but I guess this is mainly because I am missing something in the template declaration.
In the end I am hoping to use this class by returning
return empty_reference<std::string, std::string()>();
So I have three questions here;
could this be possible
how do I make this work, what should I turn 'decltype(T) V' into to tell the compiler that V should be of type T while still being evaluated during compilation?
and is this a good approach or is there an easier/better solution to this problem?
Not exactly the same, but you can get your string as a function parameter instead of as a return value and rely on the fact that temporaries bind to const references.
As an example:
#include <string>
#include <iostream>
#include <utility>
struct S {
template<typename F>
void get(bool b, F &&f) {
std::forward<F>(f)(b ? s : "");
}
std::string s{"foo"};
};
int main() {
S s;
s.get(true, [](const auto &str) { std::cout << str << std::endl; });
s.get(false, [](const auto &str) { std::cout << str << std::endl; });
}
This can be a valid alternative if libraries like Boost are not already part of your project and you don't want to include them.
Otherwise, as others have mentioned, you can pick up an upcoming utility called std::optional and combine it with std::reference_wrapper as it follows:
#include <string>
#include <iostream>
#include <experimental/optional>
#include <functional>
struct S {
std::experimental::optional<std::reference_wrapper<std::string>> get(bool b) {
return b ? std::ref(s) : std::experimental::optional<std::reference_wrapper<std::string>>{};
}
std::string s{"foo"};
};
int main() {
S s;
auto opt1 = s.get(true);
std::cout << (opt1 ? opt1->get() : "-") << std::endl;
auto opt2 = s.get(false);
std::cout << (opt2 ? opt2->get() : "-") << std::endl;
}
Pretty ugly indeed. Note that a std::optional should be verified through its operator bool or the member method has_value to be sure that it contains a value.
Unfortunately you cannot use directly a std::reference_wrapper as return value, for it cannot be (let me say) _empty). In other terms, if you want to construct such an object, you must pass a valid reference to its constructor.
Another approach would be by using a template class like the following one:
#include <string>
#include <type_traits>
#include <iostream>
template<typename T>
struct defval {
static const std::decay_t<T> value;
};
template<typename T>
const std::decay_t<T> defval<T>::value = T{};
struct S {
const std::string & get(bool b) {
return b ? str : defval<std::string>::value;
}
std::string str{"foo"};
};
int main() {
S s;
std::cout << s.get(true) << std::endl;
std::cout << s.get(false) << std::endl;
}
Note that you must specialize it for those types that are not default constructible.
References must be bound to an object. So you can't return a reference in your case. Your options are:
Return a (non-owning) pointer.
Return something like boost::optional, which can hold a reference (unlike the soon to be added std::optional).
So at some point I figured it out, at least I guess.
template<typename T>
struct empty_reference {
using type = T;
static const type static_object_;
operator const type&() {
return static_object_;
}
};
template<typename T>
const typename empty_reference<T>::type
empty_reference<T>::static_object_ = {};
The concept is that the compiler will 'generate' one static 'static_object_' member for all types you use it for. Therefore, for any type you used the empty_reference for, a static object is generated in your application and returned when they are requested (i.e. if you return empty_reference<int> in two different files, a reference to the same int value will be returned).
The key was to remove the 'decltype(T) V' completely and use the universal initialization (i.e. {}) to make sure that any 'empty' constructor is called to initialize the object.
The downside is the reference needs to be constant (otherwise you can edit your 'empty reference') and the type is required to be constructable using an empty constructor.
So I guess the only question remaining is whether it is a good idea (I am not going to just my own ideas). Happy to receive any other suggestions/feedback :-)

Const keyword with function signature

Here is my simple code:
#include <iostream>
using namespace std;
class alloc { };
template <typename T, typename Alloc = alloc>
class vector
{
public:
void swap(vector<T,Alloc> &v) { cout << "swap()" << endl; }
};
template <typename T, typename Alloc>
void swap(const vector<T,Alloc> &v1,const vector<T,Alloc> &v2)
{
v1.swap(v2);
}
int main()
{
vector<int> x;
vector<int> y;
swap(x,y);
return 0;
}
The code snippet run without problem.But i can't get any outputs
Then I delete const keyword.
void swap(vector<T,Alloc> &v1,vector<T,Alloc> &v2)
I get output swap()
I have read "The reason is that const for the parameter only applies locally within the function, since it is working on a copy of the data. This means the function signature is really the same anyways."
So i thought there is no difference between write or not write const.if i insist to write const here,how do i modify the code to get the output swap()
This is an excellent illustration of why using std should be avoided.
In order to debug this problem, remove using std, and add std:: in places where you want the behavior from the standard library. Fortunately, there is only one such place, i.e. the swap function in the template class:
void swap(vector<T,Alloc> &v) { std::cout << "swap()" << std::endl; }
Now try compiling again to see the error preventing your swap with const from being used:
prog.cpp:19:5: error: passing const vector<int> as this argument discards qualifiers
When your program was using std C++ had an alternative of picking std::swap over your own swap function when your function was not applicable. That is exactly what it did, without any warning, because it assumed that it is what you want it to do.
The error also tells you what to do in order to make const-qualified vectors be accepted: add const to the parameters of vector::swap, like this:
void swap(const vector<T,Alloc> &v) const { std::cout << "swap()" << std::endl; }
Now your program compiles and runs again (demo).

Why can't my trait template class lookup operator<< for llvm::StringRef?

Following the question How can I detect if a type can be streamed to an std::ostream? I've written a trait class that says if some type can be streamed to an IO stream. The trait has seemed to work well until now that I've discovered a problem.
I'm using the code inside a project that uses LLVM and I'm using their StringRef class (which is similar in spirit to the proposed std::string_view). Here is a link to the Doxygen doc for the class, from where you can find it's declaration header file if needed. Since LLVM doesn't provide an operator<< to stream StringRef objects to std streams (they use a custom lightweight stream class), I've written one.
However, when I use the trait it doesn't work if my custom operator<< is declared after the trait (this happens because I have the trait in one header and the operator<< function in another one). I used to think that the lookup in template instantiations worked from the point of view of the instantiation point, so I thought it should work. Actually, as you can see below, with another class and its custom operator<<, declared after the trait, everything works as expected (that's why I've discovered this problem only now), so I can't figure out what makes StringRef special.
This is the complete example:
#include <iostream>
#include "llvm/ADT/StringRef.h"
// Trait class exactly from the cited question's accepted answer
template<typename T>
class is_streamable
{
template<typename SS, typename TT>
static auto test(int)
-> decltype(std::declval<SS&>() << std::declval<TT>(),
std::true_type());
template<typename, typename>
static auto test(...) -> std::false_type;
public:
static const bool value = decltype(test<std::ostream,T>(0))::value;
};
// Custom stream operator for StringRef, declared after the trait
inline std::ostream &operator<<(std::ostream &s, llvm::StringRef const&str) {
return s << str.str();
}
// Another example class
class Foo { };
// Same stream operator declared after the trait
inline std::ostream &operator<<(std::ostream &s, Foo const&) {
return s << "LoL\n";
}
int main()
{
std::cout << std::boolalpha << is_streamable<llvm::StringRef>::value << "\n";
std::cout << std::boolalpha << is_streamable<Foo>::value << "\n";
return 0;
}
Contrary to my expectations, this prints:
false
true
If I move the declaration of the operator<< for StringRef before the trait declaration, it prints true.
So why is this strange thing happening and how can I fix this issue?
As mentioned by Yakk this is simply ADL: Argument Dependent Lookup.
If you don't want to bother, just remember that you should always write a free function in the same namespace as at least one of its arguments. In your case, since it's forbidden to add functions to std, it means adding your function into the llvm namespace. The fact that you needed to qualify the StringRef argument with llvm:: was a dead give away.
The rules of function resolution are fairly complex, but as a quick sketch:
name lookup: collects a set of potential candidates
overload resolution: picks the best candidate among the potentials
specialization resolution: if the candidate is a function template, check for any specialization that could apply
The name lookup phase which we are concerned with here is relatively simple. In short:
it scans the argument's namespaces, then their parents, ... until it reaches the global scope
then proceeds by scanning the current scope, then its parent scope, ... until it reaches the global scope
Probably to allow shadowing (like for any other name lookup), the lookup stops at the first scope in which it encounters a match, and haughtily ignore any surrounding scope.
Note that using directives (using ::operator<<; for example) can be used to introduce a name from another scope. It is burdensome though, as it puts the onus on the client, so please don't rely on its availability as an excuse for sloppiness (which I've seen done :x).
Example of shadowing: this prints "Hello, World" without raising an ambiguity error.
#include <iostream>
namespace hello { namespace world { struct A{}; } }
namespace hello { void print(world::A) { std::cout << "Hello\n"; } }
namespace hello { namespace world { void print(A) { std::cout << "Hello, World\n"; } } }
int main() {
hello::world::A a;
print(a);
return 0;
}
Example of interrupted search: ::hello::world yielded a function named print so it was picked out even though it does not match at all and ::hello::print would have been a strictly better match.
#include <iostream>
namespace hello { namespace world { struct A {}; } }
namespace hello { void print(world::A) { } }
namespace hello { namespace world { void print() {} } };
int main() {
hello::world::A a;
print(a); // error: too many arguments to function ‘void hello::world::print()’
return 0;
}

Implicit argument conversion ambiguity in non-member functions overloads with std::function?

Editted - please skip to the edit, which has the real problem
I frequently run into situations in my string helper library of stand-alone functions, where I provide overloads of a function with versions that take a char and versions that take a std::string.
The problem is, the overload then becomes ambiguous when passed a string literal (const char*).
Example:
void myFunc(const std::string &subStr);
void myFunc(char character);
These two functions are implemented differently, one optimized for strings and one for a single char.
Howsoever, trying to call myFunc("literal") results in ambiguity, despite me always wanting it to call the std::string version.
This forces me to provide void myFunc(const char *str) versions of my overloads, which only are stubs like:
void myFunc(const char *str)
{
myFunc(std::string(str));
}
Is there some way to make these stub functions unnecessary? I'd like to just be able to make void myFunc(char c) 'explicit', but you can't make non-constructor non-member functions explicit. Which would solve the problem instantly. =(...
(As an aside, why can't you make standalone functions explicit?)
Edit:
You know what they say about programmers coding too late into the night! (If you remember the joke, tell me, because I was too sleepy when I originally heard it and I've since forgotten it)
The real problem
I'm using MinGW v4.7.2, and the problem was alot different then my post originally assumed.
The problem is, I have several overloads. Yes, this example works fine:
void myFunc(const std::string &subStr);
void myFunc(char character);
But if you add an std::function overload, it breaks down:
void myFunc(const std::string &subStr);
//Not actually part of the problem; I was confused by part of the error message highlighting this function.
//void myFunc(char character);
void myFunc(std::function<bool(char)); //<-- The real problem
My string library has std::string, char, and std::function overloads (and occasionally a few more overloads for simplifying functions with alot of optional parameters).
When I have std::function as an overload, I get this error message:
error: call of overloaded ‘myFunc(const char [15])’ is ambiguous
candidates are:
void myFunc(char) <near match>
no known conversion for argument 1 from ‘const char [15]’ to ‘char’
void myFunc(std::function<bool(char)>)
void myFunc(const string&)
The myFunc(char) was how I initially got confused last night. Removing that overload from the code, I get the error message:
error: call of overloaded ‘myFunc(const char [15])’ is ambiguous
candidates are:
void myFunc(std::function<bool(char)>)
void myFunc(const string&)
Here's a self-contained compilable example.
How can I make a string literal choose the std::string over the std::function?
It's probably ambiguous because std::function's constructor is templated and is designed to take a function pointer, among other things.
Since my string library, specifically, uses only std::function<bool(char)> and std::function<bool(const std::string&)>, already typedef'd, I could inherit those into a class with an explicit constructor.
Is there other suggestions or options available?
Can you update your compiler? Your example compiles as expected in g++4.8 and above.
This is actually is a current defect report in the C++ standard. See 2132. std::function ambiguity. It is currently in review status, but most likely will be accepted. This will make sure that non-Callable types like your example never participate in overload resolution:
These constructors shall not participate in overload resolution unless
f is Callable
Currently g++4.8 and above implements this.
You did not provide self-contained repro so it's hard to say what's wrong.
But here are a couple of guesses:
You have a bug in compiler (unlikely)
You don't call character overload properly. You should call it like that: myFunc('c').
You provided incorrect calling code or incorrect method signature(s).
I guess following code snippet should explain what should be happening and how to declare and call methods properly. Note myOtherFunc trick with capturing literal. It can be done better w/o template function, with smart wrapper around string, but I'll leave that out.
You can also try it on your compiler and see if it works, then we'll know if you have compiler problem.
Live code: http://codepad.org/gzB7xWs2
#include <string>
#include <iostream>
using namespace std;
void myFunc(char c) {
cout << "myFunc called with char" << endl;
}
void myFunc(const string& s) {
cout << "myFunc called with string" << endl;
}
void myOtherFunc(char c) {
cout << "myOtherFunc called with char" << endl;
}
void myOtherFunc(const string& s) {
cout << "myOtherFunc called with string" << endl;
}
template <size_t StingSizeWithNullTerminator>
void myOtherFunc(const char (&buf)[StingSizeWithNullTerminator]){
cout << "myOtherFunc called with literal of size " << (StingSizeWithNullTerminator - 1) << endl;
}
int main() {
myFunc("string");
myFunc('c');
myFunc(string("std string"));
myOtherFunc("string");
myOtherFunc('c');
myOtherFunc(string("string"));
return 0;
}
Output:
myFunc called with string
myFunc called with char
myFunc called with string
myOtherFunc called with literal of size 6
myOtherFunc called with char
myOtherFunc called with string
Update
Now, with the example, it's clear what the problem is.
The problem is that there is no method with exact signature that accepts char[15]. And compiler needs to perform conversion.
The problem is that it can either convert to std::string or to std::function (because std::function has template constructor which accepts any type, including char[15]). Therefore it can't choose which conversion to use and gives up.
Therefore there's no clean solution for that as far as I know of, but here are some no-so-clean:
Use explicit conversion to std::string when calling methods
Ask yourself (and maybe tell us), what's the reason for having myFunc which accepts both strings and functions. Maybe there's a problem with design and you can avoid having functions with same names.
If you only need to accept bool(&)(char) function, you can use custom wrapper instead (see example below)
Example for 3rd option (http://ideone.com/o0NqUf):
#include <iostream>
#include <functional> //Required for std::function.
struct Callback
{
Callback(bool (&func)(char)): m_func(func)
{}
bool operator()(char c) { return m_func(c); }
bool (&m_func)(char);
};
void myFunc(Callback seperatorFunc)
{
std::cout << "Callback overload" << std::endl;
}
void myFunc(const std::string &separator)
{
std::cout << "std::string overload" << std::endl;
}
bool testCallback(char)
{
return true;
}
int main()
{
myFunc("String literal");
myFunc(std::string("std::string"));
myFunc(testCallback);
return 0;
}
Output:
std::string overload
std::string overload
Callback overload
You should be able to SFINAE yourself very easily out of this one:
template <typename F>
auto myFunc(F f) -> decltype(!f('0'), std::function<bool(char)>(f), void()) {
std::cout << "std::function<bool(char)> overload" << std::endl;
}
Or, using a C++03 compiler (possibly using tr2/type_traits or Boost Type Traits if your compiler doesn't yet have them):
template <typename F>
void myFunc(F f, typename std::enable_if<std::is_constructible<
std::function<bool(char)>, F>::value>::type* = nullptr)
{
std::cout << "std::function<bool(char)> overload" << std::endl;
}
Proof it works:http://ideone.com/Q87JsV
#include <iostream>
#include <type_traits>
#include <functional>
#if 1
template <typename F>
auto myFunc(F f) -> decltype(!f('0'), std::function<bool(char)>(f), void()) {
std::cout << "std::function<bool(char)> overload" << std::endl;
}
#else
template <typename F>
void myFunc(F f, typename std::enable_if<std::is_constructible<
std::function<bool(char)>, F>::value>::type* = nullptr)
{
std::cout << "std::function<bool(char)> overload" << std::endl;
}
#endif
void myFunc(const std::string &seperator) {
std::cout << "std::string overload" << std::endl;
}
bool testCallback(char) {
return true;
}
int main()
{
myFunc("String literal");
myFunc(std::string("std::string"));
myFunc(testCallback);
}
Output:
std::string overload
std::string overload
std::function<bool(char)> overload

Cannot overload function

So I've got a templatized class and I want to overload the behavior of a function when I have specific type, say char. For all other types, let them do their own thing. However, c++ won't let me overload the function.
Why can't I overload this function? I really really do not want to do template specialization, because then I've got duplicate the entire class.
Here is a toy example demonstrating the problem: http://codepad.org/eTgLG932
The same code posted here for your reading pleasure:
#include <iostream>
#include <cstdlib>
#include <string>
struct Bar
{
std::string blah() { return "blah"; }
};
template <typename T>
struct Foo
{
public:
std::string doX()
{
return m_getY(my_t);
}
private:
std::string m_getY(char* p_msg)
{
return std::string(p_msg);
}
std::string m_getY(T* p_msg)
{
return p_msg->blah();
}
T my_t;
};
int main(int, char**)
{
Foo<char> x;
Foo<Bar> y;
std::cout << "x " << x.doX() << std::endl;
return EXIT_SUCCESS;
}
Thank you everyone for your suggestions. Two valid solutions have been presented. I can either specialize the doX method, or specialize m_getY() method.
At the end of the day I prefer to keep my specializations private rather than public so I'm accepting Krill's answer.
You can specialize just one function out of an entire template class on a specific type without specializing the entire class. It would look like this:
template <> void Foo<char>::doX() {
/* custom implementation here */
}
You rarely see this in practice, but this is totally legal C++ code.
Hope this helps!
std::string m_getY(char* p_msg)
{
return std::string(p_msg);
}
std::string m_getY(T* p_msg)
{
return p_msg->blah();
}
The problem here is that when T is char, you end up with two functions with identical signature.
You can make your method m_getY a member function template. And them make specialization of this function template for char* or simply define a method with a char* argument. In this case you will not have to duplicate the whole class.
std::string m_getY(char* p_msg)
{
return std::string(p_msg);
}
template<typename U>
std::string m_getY(U* p_msg)
{
return p_msg->blah();
}
will not conflict with each other (and the former is not a specialisation of the latter, as it is not a template)