I stumbled on a strange compilation problem. I want to process a list of strings, using std::for_each. The following simplified code illustrates the problem :
# include <list>
# include <string>
# include <algorithm>
using namespace std ;
void f(wstring & str)
{
// process str here
}
void g(wstring & str, int dummy = 0)
{
// process str here, same as f, just added a second default dummy argument
}
int main(int, char*[])
{
list<wstring> text ;
text.push_back(L"foo") ;
text.push_back(L"bar") ;
for_each(text.begin(), text.end(), f) ; // OK, fine :)
for_each(text.begin(), text.end(), g) ; // Compilation error, complains about
// g taking 2 arguments, but called within std::for_each
// with only one argument.
// ...
return 0 ;
}
I tested using MinGW 4.5.2 and MSVC10, both reported the same error message. Originally, I wanted to use boost::algorithm::trim as a processing function passed to std::for_each, but I found that it takes two arguments, the first being mandatory (the string to process) and the second one is optional (a locale providing a definition for space chars).
Is there any way to keep things clean when using std::for_each(and other standard algorithms) when having functions or methods with default arguments ? I found a way to make it work, but it is no more clear and easily understandable, so a for loop begins to seem easier ...
# include <list>
# include <string>
# include <algorithm>
# include <boost/bind.hpp>
# include <boost/algorithm/string.hpp>
using namespace std ;
using namespace boost ;
// ... somewhere inside main
list<wstring> text ;
for_each(text.begin(), text.end(), bind(algorithm::trim<wstring>, _1, locale()) ;
// One must deal with default arguments ...
// for_each(text.begin(), text.end(), algorithm::trim<wstring>) would be a real pleasure
Thanks for any help !
Note : I just started learning English, sorry for mistakes :)
Default arguments are just a code-generation tool and not part of the function signature, so you can't really get around that. You could wrap your function in a function object, but that's precisely what bind already does for you.
However, in C++0x you can conveniently store the result (and use std::bind) to maybe make the code a bit more readable:
auto trimmer = std::bind(boost::algorithm::trim<std::wstring>, std::placeholders::_1, std::locale());
std::for_each(text.begin(), text.end(), trimmer);
(The reason you don't want to do that in C++98/03 is that the return type of bind is something rather unsightly, and you wouldn't be doing anyone a favour by spelling it out.)
Alternatively, again in C++0x, you could use a lambda:
std::for_each(text.begin(), text.end(), [](std::wstring & s){ boost::algorithm::trim<std::wstring>(s); });
Related
I'm trying to reproduce (*) something similar to Python fstring, or at least its format function (and while at it, I'd like to implement something like its "Mini-language").
(*) N.B.: please note that I am aware of the existence of the standard lib's format library, as well as the existence of the {fmt} library; but,
a: neither the g++ (11.2.1) nor the clang++ (12.0.1) that I have on my machine can compile code including <format>, and
b: I don't want to use the excellent {fmt} lib, because I'm precisely trying to do my own thing/thingy.
I'm going to use a string in input to my format object, and any number of additional arguments, like that:
// First, some vars
std::string stef{"Stéphane"};
std::string cpp{"C++"};
int ilu3t{3000};
// Then the big deal
std::string my_fstring = badabwe::format(
"My name is {stef}, and I love {cpp} {ilu3t} !",
cpp,
stef,
ilu3t
);
// Obviously, only the 1st parameter is positional!
// my_fstring should now be:
// My name is Stephane, and I love C++ 3000 !
That's one of the first problem, I have to solve. I think this process is called reflection (please let me know if it's the case).
Next I need to handle a variable number of arguments; the 1st parameter is the only positional and mandatory one (I'm still trying to find a way to iterate over a parameter pack), but its a subject for another question.
A function is not aware of name of parameters passed it. The parameter doen't even have to have a name:
void foo(int x); // name of the argument is x
foo(42); // 42 has no name
As suggested in a comment, if you want some mapping between strings (values to be replaced) and strings (their names) then you can use a map. To avoid the caller to spell out this mapping you can use a macro (usually to be avoided, but for now its the only way to get the name of a variable as a string):
#include <iostream>
#include <string>
#include <unordered_map>
using token_t = std::unordered_map<std::string,std::string>;
std::string format(const std::string& tokenized,const token_t& token) {
return "test";
}
#define tokenize(token) { #token , to_string(token) }
using std::to_string;
std::string to_string(const std::string& str) { return str; }
int main() {
std::string stef{"Stéphane"};
std::string cpp{"C++"};
int ilu3t{3000};
std::string my_fstring = format(
"My name is {stef}, and I love {cpp} {ilu3t} !",
{
tokenize(cpp),
tokenize(stef),
tokenize(ilu3t)
}
);
}
I assumed that you can use std::to_string, though there is no std::to_string(const std::string&) hence I added a custom implementation.
so I have a piece of old code that I'm trying to debug
#include <string>
#include <map>
int main()
{
std::map<std::wstring, std::wstring> filters;
...
for (auto filterIter : filters)
{
...
wchar_t* nameArray = new wchar_t[filterIter.first.size() + 1];
std::copy(filterIter.first.begin(), filterIter.first.end(), nameArray);
nameArray[filterIter.first.size()] = '\0';
...
LPCWSTR pszName = nameArray;
}
getchar();
return 0;
}
The problem here is that I get this warning saying:
warning C4996: 'std::copy::_Unchecked_iterators::_Deprecate': Call to 'std::copy' with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'
I want to resolve this warning without having to silence the warning. I know that the problem is the fact that nameArray is a regular pointer not an Output iterator . And std::copy wants me to put in an output iterator in std::copy last parameter. I want to make this code comply with what std::copy wants me to do. What's an elegant way of accomplishing that?
I did think about making my own iterator class but is that really that elegant?
I'm going to answer this question as I figured I think I've figured it out and it would help others who runs into this problem:
it turns out, this is a very C way of copying. Since LPCWSTR is simply a wchar_t under the hood, I end up just doing this and I don't get compiler errors anymore. I'm going to run test to make sure this function still behaves the same.
Note: I didn't write this code, this is simply a legacy code I'm looking at.
Here is the updated version
#include <string>
#include <map>
int main()
{
std::map<std::wstring, std::wstring> filters;
...
for (auto filterIter : filters)
{
...
LPCWSTR pszName = filterIter.first.c_str();
...
}
getchar();
return 0;
}
I can't seem to find any relevant information on the following sort of thing.
Say that you have a program with numerous methods (for example, a custom set of tests).
How could you loop through them based on something like the following pseudo-code
for(int i= 0; i < 10 ; i ++)
{
function(i)();
}
so that it will go through this loop and therefore launch methods function0, function1, function2, function3, function4, function5, function6, function7, functuin8, function9.
If there are ways to also do this in C# or Java, then information for them also would be appreciated.
In C++, the only way I can think of is to use of an array of function pointers. See here.
For Java, which supports Reflection, see this. And for C#, which also supports Reflection, this.
The language feature you would need for this is called "Reflection", which is a feature C++ does not have. You will need to explicitly name the functions you want to call.
Well, if you have an array of function pointers, you can do something like this:
void (*myStuff[256])(void);
And then when you want to call each function just dereference each of them as you iterate.
Keep in mind that every function in your array must have the same parameter signature and return type.
Here's a solution using Boost.Function and Boost.Bind in which the loop doesn't need to worry about the parameter signatures of the functions you are calling (I haven't tested it in a compiler, but I have very similar code in a project which I know works):
#include <vector>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using std::vector;
using boost::function;
using boost::bind;
void foo (int a);
void bar (double a);
void baz (int a, double b);
int main()
{
// Transform the functions so that they all have the same signature,
// (with pre-determined arguments), and add them to a vector:
vector<function<void()>> myFunctions;
myFunctions.push_back(bind(&foo, 1));
myFunctions.push_back(bind(&bar, 2.0));
myFunctions.push_back(bind(&baz, 1, 2.0));
// Call the functions in a loop:
vector<function<void()>>::iterator it = myFunctions.begin();
while (it != myFunctions.end())
{
(*it)();
it++;
}
return 0;
}
Note that you can do the loop much easier if your compiler supports C++11:
// Call the functions in a loop:
for (const auto& f : myFunctions)
{
f();
}
Boost.Bind also supports passing in certain parameters dynamically instead of binding them to pre-determined values. See the documentation for more details. You could also trivially alter the above code to support return values (if they are of the same type), by replacing void with the return type, and altering the loop to do something with the returned value.
I have a code like below:
typedef std::set<std::string> set_of_strings;
set_of_strings s1, s2, result1;
some_func()
{
s1.insert("1-2");
s1.insert("1-1");
s1.insert("3-4");
s2.insert("1-2");
s2.insert("1-3");
s2.insert("3-4");
set_of_strings::iterator s1_begin = s1.begin();
set_of_strings::iterator s1_end = s1.end();
set_of_strings::iterator s2_begin = s2.begin();
set_of_strings::iterator s2_end = s2.end();
set_of_strings::iterator result_begin = result1.begin();
td::insert_iterator<set_of_strings> result_inserter = std::inserter(result1, result_begin);
set_difference(s1_begin, s1_end,s2_begin, s2_end,result_inserter); //This is the problem line
}
The compilation error that i get is overloading ambiguity std::copy(....
the problem is set_difference returns like
return copy(first1,last1,result);
Please check here for the algo rithm of set_difference.
set_difference returns like :
copy(..)
if it is std::copy there would not be any problem.
i tried with putting my statement inside a block like below:
{
using namespace std;
set_difference(s1_begin, s1_end,s2_begin, s2_end,result_inserter);
}
but this doesn't work.
I know that the problem is with the copy function which we have written for our own purpose and its used at many places.Here i want to use std::copy.
could anybody pls help.
If you've written your own copy function that the compiler can see in the same scope as std::copy and it's a possible candidate, then sure that would cause an ambiguity.
There's no magic flag you can set to make it use std::copy, but I think if you put your own copy in a namespace and don't using that namespace, the compiler won't be able to find it and fall back to std::copy. That said, I don't think I can understand a case where you would want to create an alternate copy that works for set iterators, and if you wrote a generic one it probably shouldn't be called copy because it'll cause no end of ambiguity errors like this one.
I was following some information from this: How to find the first character in a C++ string
When I tried to implement it into my code, I got the error not1 was not declared in this scope.
void ASTree::indent(int ind, int inc) {
std::string theText;
for (std::vector<ASTree*>::const_iterator i = child.begin(); i != child.end(); ++i) {
switch ((*i)->nodeType) {
case category:
(*i)->indent(ind + inc, inc);
break;
case token:
{
//out << std::setw(indent) << " ";
theText = (*i)->text; // << std::endl;
std::string::iterator firstChar = std::find_if(theText.begin(), theText.end(), std::not1(std::isspace));
theText.erase(theText.begin(), firstChar);
(*i)->text = theText;
}
break;
case whitespace:
//out << (*i)->text;
break;
}
}
}
I'm somewhat new to C++ and working on these projects for in class.
Have you included this header:
#include <functional>
Also, use std::not1, not just not1, for it is defined in std namespace.
I hope you've not written using namespace std in your code, which is a bad idea anyway.
Alright after reading this comment by you:
get yet another error. :) no matching function for call to ânot1(<unresolved overloaded function type>)â I also updated the code above to show you my current
I guess there is another function with name isspace is present in std namespace, which is causing the problem while resolving the names.
So here are two solutions. Try one by one:
Use just ::isspace. Without using std. Just ::isspace. See if it works!
Or, cast explicitly to help the compiler in selecting the desired overload, as
std::not1(((int)(*)(int))(std::isspace));
Since the casting looks very clumsy, you can use typedef also, as:
//define this inside the function, or outside the function!
typedef int (*fun)(int);
//then do this:
std::not1((fun)(std::isspace))
I hope this should help you.
A similar problem has been seen before, see this:
"Unresolved overloaded function type" while trying to use for_each with iterators and function in C++
To use std::not1 you need to #include <functional>, also you need to prefix it with the namespace properly (if you don't have a using directive):
std::string::iterator firstChar = std::find_if(
theText.begin(),
theText.end(),
std::not1(isspace));