I'm getting some errors when using strcpy_s and can't figure out what I'm doing wrong.
The code:
Player.hpp:
string name;
Player(string);
Player.cpp:
Player::Player(string newName)
{
strcpy_s(name, name.size(), newName);//error is here
health = 20;
}
The errors:
Too many arguments in function call
No instance of overloaded function 'strcpy_s' matches the argument list
You cannot use strcpy_s to copy std::string. Actually, you just need to do:
Player::Player(string newName) {
name = newName;
health = 20;
}
Even better, you could use a constructor initialization list:
Player::Player(string newName) : name(newName), health(20) {}
As a reference, here you have a detailed description of std::string class.
This URL states that the C++ version only uses template overloaded
functions (2 arguments not 3):
http://msdn.microsoft.com/en-us/library/td1esda9%28v=vs.80%29.aspx
template
errno_t strcpy_s(
char (&strDestination)[size],
const char *strSource
); // C++ only
According to this URL:
In C++, using these functions is simplified by template overloads; the overloads can infer buffer length automatically (eliminating the need to specify a size argument) and they can automatically replace older, non-secure functions with their newer, secure counterparts. For more information, see Secure Template Overloads.
(As stated in the prototype this function is for char* arguments - not for string data types)
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.
curious to know when shorthand notation will cause panic ?
I know this is ok:
class Player{
private:
std::string ScreenName, SignUpDate, PublicKey, PrivateKey;
int Id, CreditBalance, GlobalRank, RegionalRank, localRank;
static int TotalPlayers, TotalLivePlayers;
}
what about this inside function parameters, (trying to learn to code like the pros )
void SetAllValues(
std::string NewScreenName, NewSignUpDate, NewPublicKey, NewPrivateKey,
NewPlayerId, NewCreditBalance, NewGlobalRank, NewRegionalRank, NewlocalRank
);
Your second notation would break the language: you are allowed to specify parameter types in a function parameter list and omit the parameter names.
With your proposal, there would be no way of distinguishing that.
(Finally, it may be better to recast your SetAllValues function as a constructor.)
I created a function like:
void triangle(int n, int start=1, int spcs=0, char dec_y='n', char lf='#',char decf='o') {
//some code
}
I wanted to know is there any way that I could call this function like this:
triangle(9, dec_y='y', lf='&');
without doing this:
void triangle2(int nn, char d_ec_y, char llf) {
triangle(nn, 1, 0, d_ec_y, llf, 'o');
}
// then in main simply
triangle2(9, 'y', '&');
You can't change the order of the parameters. So you can't do what you want directly. You have three options:
One that you don't want to.
You can pass the parameters as structure. The struct can have default values. And you can only alter the ones which you want before calling the function.
For example:
struct params
{
params(int n_)
:n(n_)
{
}
int start=1;
int spcs=0;
char dec_y='n';
char lf='#';
char decf='o';
};
...
params p(0);
p.dec_y='y';
p.lf='&';
triangle(p);
You can use boost::parameter which provides exactly what you want. Check this question for a sample usage.
No, c++ requires that any parameters for which the default parameter will be used come after all specified parameters.
In some circumstances this can be worked around by having multiple overloads. But due to argument ambiguity that is not always possible. The idea is to leave out some of the middle arguments, as in:
void foo(int, char const *, int =0);
void foo(int, int=0);
This pair always requires the first int but allows that to be followed by either a string or another int, and if the string version is used still allows the final int argument.
Using some advanced meta-programming it is actually possible to make all the arguments optional and to supply them in any order without declaring any overloads. For example this is implemented in boost.process API:
namespace bp = ::boost::process;
bp::environment env{::boost::this_process::environment()};
bp::child ch0("cmd", env); // ok
bp::child ch1("cmd", env, bp::windows::hide); // fine too
bp::child ch2("cmd", bp::windows::hide, env); // still fine
bp::child ch3("cmd", bp::windows::hide); // no problem
The idea behind this is that each supported argument is wrapped into a trait class that supplies manipulation method(s) and all those calls invoke the same template function which invokes manipulation method for each supplied argument.
I would like to call the following code in C++, which I cannot change:
void getAge(char *name)
{
// do something
}
When I call it with getAge("hello");, it has the following warning:
warning: deprecated conversion from string constant to 'char*'
but there is no warning in C code. What is the difference, and how do I change the call to avoid the warning in C++?
the function […] can not be changed
Then write a wrapper around the function and copy the string – or, if you feel lucky (= you know that the string won’t be modified inside the original function), explicitly cast away const-ness:
void getAge(char const* name) {
the_namespace::getAge(const_cast<char*>(name));
}
If you’re unsure whether the function modifies its parameters, use something like the following – however, if that’s the case then calling the function with a string literal (getAge("hello")) would have been invalid anyway.
void getAge(char const* name) {
std::string buffer(name);
the_namespace::getAge(&buffer[0]);
}
Here we copy the string into a modifiable buffer and pass an address to its first character to the original function.
The safest way is to copy the string, then call the C function:
void getAgeSafe(const char* name)
{
std::vector<char> tmp = name?
std::vector<char>(name, name+1+strlen(name))
:std::vector<char>();
getAge( tmp.data() );
}
and call getAgeSafe from your C++ code.
A less safe way that relies on the C code never modifying the char* name would be to const_cast, again in a "wrapping" function:
void getAgeUnsafe(const char* name)
{
getAge( const_cast<char*>(name) );
}
but this time the name is more scary, as is the operation. If you call getAge with a compile time constant string like "bob", if getAge modifies its input, undefined behavior results (this is true in both C and C++ -- C++ at least warns you about it).
You can try getAge((char*)"hello").
In c++ you can write it like this,
void getAge(string name)
{
// do something
}
and also include the header file #include<string> because you are using string now
I have an instance method that populates a vector of strings. I am trying to find the one vector entry that contains a specific substring (for now, that substring is fixed - simple).
I have a .h:
namespace Data
{
namespace Shared
{
class Logger
{
public:
bool FindLogDirectoryPredicate(const string &str);
int GetLogDirectory(string logConfigFile, string& logDirectory);
...
}
}
}
and .cpp:
#include <algorithm>
#include <vector>
#include "Logger.h"
bool Logger::FindLogDirectoryPredicate(const string &str)
{
// Return false if string found.
return str.find("File=") > 0 ? false : true;
}
int Logger::GetLogDirectory(string logConfigFile, string& logDirectory)
{
vector<string> fileContents;
...
vector<string>::iterator result = find_if(fileContents.begin(), fileContents.end(), FindLogDirectoryPredicate);
...
}
Compiling this in Visual Studio 2010, I receive:
Error 7 error C3867: 'Data::Shared::Logger::FindLogDirectoryPredicate': function call missing argument list; use '&Data::Shared::Logger::FindLogDirectoryPredicate' to create a pointer to member Logger.cpp 317 1 Portability
Throwing an & in front of the function ref in the find_if call then results in:
Error 7 error C2276: '&' : illegal operation on bound member function expression Logger.cpp 317 1 Portability
I did try to put the predicate function outside the class, but that didn't seem to work - gave me a function not found error. Tried qualifying the predicate with the class name... that gave me a different error in algorithm (header):
Error 1 error C2064: term does not evaluate to a function taking 1 arguments c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\algorithm 83 1 Portability
The example I was following from here seems to indicate that this is relatively simple.... so what am I doing wrong?
The problem is that FindLogDirectoryPredicate is an instance method: it's not enough to specify its name, you somehow have to specify which object that method should be called on. Now the answer to this question is obvious to us (this), but not to the compiler.
The classic way to do this is with
find_if(fileContents.begin(),
fileContents.end(),
bind1st(mem_fun(&Logger::FindLogDirectoryPredicate), this));
What's going on here?
mem_fun "converts a member function to a function object". That is, it creates an instance of a type (what type exactly is unspecified, but we don't care) that exposes operator() (this is what we do care about!). This operator expects the first parameter to be a pointer to an instance of the type that defines the member function; here, that would be an instance of Logger.
bind1st then takes this function object that takes two parameters (first is the pointer to instance, second is the original const string & parameter) and returns a different function object that takes just one parameter (the const string &). The other parameter is fixed to the value of bind1st's second argument (this).
Alternatively, if you can make FindLogDirectoryPredicate static then there's no longer any need to specify which instance to call it on, so the problem will automatically go away.
Make the predicate static
class Logger
{
public:
static bool FindLogDirectoryPredicate(const string &str);
}
Or perhaps, use a lambda.
result = std::find_if(begin(), end(), [&this] (const std::string& s)
{ return FindLogDirectoryPredicate(s); } );
You can also use a std::mem_fun (and related <functional> stuff) if you must use C++98/C++03
result = std::find_if(begin(), end(),
std::bind1st(std::mem_fun(&Logger::FindLogDirectoryPredicate), this) );
Make your predicate a static class member.
static bool FindLogDirectoryPredicate(const string &str);