I wonder if there is any way to differentiate the function calls (with arrays as parameters) shown in the following code:
#include <cstring>
#include <iostream>
template <size_t Size>
void foo_array( const char (&data)[Size] )
{
std::cout << "named\n";
}
template <size_t Size>
void foo_array( char (&&data)[Size] ) //rvalue of arrays?
{
std::cout << "temporary\n";
}
struct A {};
void foo( const A& a )
{
std::cout << "named\n";
}
void foo( A&& a )
{
std::cout << "temporary\n";
}
int main( /* int argc, char* argv[] */ )
{
A a;
const A a2;
foo(a);
foo(A()); //Temporary -> OK!
foo(a2);
//------------------------------------------------------------
char arr[] = "hello";
const char arr2[] = "hello";
foo_array(arr);
foo_array("hello"); //How I can differentiate this?
foo_array(arr2);
return 0;
}
The foo "function family" is able to distinguish a temporary object from a named. Is not the case of foo_array.
Is it possible in C++11 ?
If not, do you think could be possible? (obviously changing the standard)
Regards.
Fernando.
There is nothing wrong with foo_array. It's the test case that is bad: "hello" is an lvalue! Think about it. It is not a temporary: string literals have static storage duration.
An array rvalue would be something like this:
template <typename T>
using alias = T;
// you need this thing because char[23]{} is not valid...
foo_array(alias<char[23]> {});
Related
code as follows:
#include <iostream>
#include<functional>
class TestCase {
public:
template<typename ...Args>
void myfun(Args&& ...args) {
sayhello(std::forward<Args>(args)...);
}
private:
void sayhello(const std::string& v, const std::string& v2) {
std::cout <<" ---1---- " << v << "," << v2 << std::endl;
}
};
template<typename ...Args>
void test(Args&& ...args) {
TestCase a;
auto f = std::bind(&TestCase::myfun<Args...>, &a,std::forward<Args>(args)...);
f();
}
int main() {
std::string a = "1";
std::string b = "2";
test(a,b); //ok
test("1","2"); //error
return 0;
}
why std::forward not work? I tried pass value by lvalue and it work,but pass value by rvalue not work.I confused with TestCase::myfun<Args...> ,should it be TestCase::myfun<Args&&...> or something else?
The problem is similar to that in std::bind and rvalue reference.
std::bind will always copy the arguments and store them. When you use "1", "2", TestCase::myfun<Args...> is instantiated with Args = const char &[2], while the arguments are stored as const char * (due to the copy), so the error occurs since the parameter const char &[2] does not match arguments of const char *.
When you use std::string("1"), std::string("2"), TestCase::myfun<Args...> is instantiated with Args = std::string (so the parameter type is std::string &&). The error still occurs since the parameter std::string && does not match the stored arguments, which are lvalues.
As you have found, using lambda is a proper solution.
I have a structure, e.g.
struct Test
{
std::string a;
std::string b;
std::string c;
};
In another part of project I want to assign value to one od three values in structure( I want to edit it).
It is possible to do something like that:
void foo (std::string newValue, std::string nameOfStructMember)
{
for(auto & it : test) //in another part of project exist std::vector<Test> test;
{
it.nameOfStructMember= newValue;
}
}
And e.g. in main.cpp:
foo("This is my new value", "a");
No, you can't do exactly that. What you want is to resolve the adress of a member at runtime via it's name. This is called reflection and not possible in C++.
However you can do something quite similiar with member pointers.
void foo(const std::string &newValue, std::string Test::*member)
{
for(auto & it : test)
{
it.*member = newValue;
}
}
member essentially holds the offset of some member of Test, such that it.*member will access that member. You can call this function with
foo("This is my new value", &Test::a); //or &Test::b and so on
The main drawback here is obviously, that &Foo::a needs to be known at compile time. But you can easily use a std::unordered_map to map actual member names to member pointers:
std::unordered_map<std::string, std::string Test::*> mapping {
{"a", &Test::a},
// and so on
};
It seems you mean something like the following
#include <iostream>
#include <string>
#include <vector>
struct Test
{
std::string a;
std::string b;
std::string c;
};
void f( std::vector<Test> &v, std::string Test::*p, const char *s )
{
for ( auto &t : v )
{
t.*p = s;
}
}
int main()
{
std::vector<Test> v( 2 );
std::string Test::*p = &Test::a;;
f( v, p, "A" );
p = &Test::b;;
f( v, p, "B" );
p = &Test::c;;
f( v, p, "C" );
for ( const auto &t : v )
{
std::cout << t.a << ' ' << t.b << ' ' << t.c;
std::cout << '\n';
}
}
The program output is
A B C
A B C
Question:
If you want, for example, a variadic function that takes arbitrary number of parameter Args&&...args, and prints all those arguments t times. What's more is that you want t to be defaulted to 1, so it prints all args one time by default.
The first thing you would try is:
template <typename ... Args>
void foo(Args... args, unsigned t = 1) {
for (unsigned i = 0; i < t; ++i) {
(std::cout << ... << args);
}
}
Apparently this doesn't work unless you explicitly pass in the template parameters:
// Error: expected 1 argument, got 2
foo(0, "Hello, world!");
Because default parameters are treated as normal parameters while template deduction, and the parameter pack would always be empty. This prevents you from making the function useful. (Related question)
I then decided to use aggregate initialization (especially designated initializer since c++ 20) to simulate a more powerful "default parameter". It looks like this:
struct foo_t {
unsigned t = 1;
template <typename ... Args>
void operator() (Args... args) {
for (unsigned i = 0; i < t; ++i) {
(std::cout << ... << args);
}
}
};
int main() {
foo_t{}("Hello, ", "World!\n"); // prints 1 line
foo_t{ 5 }(0, "Hello, world!\n"); // prints 5 lines
return 0;
}
Moreover, this may solve people's complaint that they cannot "skip" default function parameters, with the help of c++ 20 designated intializers:
struct bar_t {
const std::string& str = "Hello, world!";
int t = 1;
void operator() () {
for (int i = 0; i < t; ++i) {
std::cout << str << std::endl;
}
}
};
int main() {
// Skips .str, using the default "Hello, World!"
bar_t{ .t = 10 }();
return 0;
}
I am wondering whether there are any potential pitfalls to do this.
Background (Can be safely ignored)
So yesterday I was wandering around SO and encountered a question (but it was later deleted) that asked about how to combine default std::source_location parameter with variadic template:
template<typename... Args>
void log(Args&&... args, const std::experimental::source_location& location = std::experimental::source_location::current()) {
std::cout << location.line() << std::endl;
}
Apparently this does not work as expected, just as stated in the question. So I came up with the following code:
struct logger {
const std::experimental::source_location& location = std::experimental::source_location::current();
template <typename... Args>
void operator() (Args&&... args) {
std::cout << location.line() << std::endl;
}
};
int main(int argc, char** argv) {
logger{}("I passed", argc, "arguments.");
return 0;
}
But found out it can do more, thus this question.
There is at least one pitfall with lifetime (extension):
const std::string& str = "Hello, world!"; create dangling pointer, (No lifetime extension for member).
Following is fine:
void repeat_print(const std::string& str = "Hello, world!", int t = 1) {/*..*/}
int main()
{
repeat_print();
}
but following is not:
struct bar_t {
const std::string& str = "Hello, world!";
int t = 1;
void operator() () const { /*..*/ }
};
int main()
{
bar_t{}();
}
You might fix bar_t to take member by value, but then you would do extra copy in some cases.
What's wrong with the code below? Latest version of g++ and clang both give error. I am sure I am missing something basic here.
#include <iostream>
struct Z
{
static const int mysize = 10;
};
Z f2();
int main()
{
std::cout << f2()::mysize << std::endl;
}
The motivation here is to be able to find out the size of an array using templates using code such as below. I know there are many ways, but just stumbled upon this idea.
template<int N> struct S
{
enum { mysize = N };
};
template<class T, int N> S<N> f(T (&)[N]);
int main()
{
char buf[10];
std::cout << f(buf)::mysize << std::endl;
}
f2() returns a value, not a type. You'd need to use the . operator on the return value instead of ::
The :: operator requires a type to be named on the lefthand side, while . allows for a value to be named. Your expression f2() does not name a type so it cannot be used in conjunction with ::.
As a side note, with a little more detail in the question we might be able to solve your real problem.
Your program contains two mistakes:
You are using the :: operator to access the member of an object. Use operator . ("dot") instead;
You declare function f2() and invoke it without defining it (this will give you a linker error).
Also, since static member variables are shared among all instances of a class (Z in this case), you do not need an object to access it;
Here is how you could fix your program:
#include <iostream>
struct Z
{
static const int mysize = 10;
};
Z f2() { return Z(); }
int main()
{
// Don't need an object to access a static variable...
std::cout << Z::mysize << std::endl;
// ...but if you really want to, do it this way...
std::cout << f2().mysize << std::endl;
}
Why don't you use this way to find out the size of array by templates:
#include <iostream>
template<int N> struct S
{
enum { mysize = N };
};
template<class T, int N> int f1(T (&)[N])
{
return N;
}
int main()
{
char buf[10];
std::cout << f1(buf) << std::endl;
}
And this one is closer to your variant:
template<class T, int N> S<N> f(T (&)[N])
{
S<N> foo;
return foo;
}
int main()
{
char buf[10];
std::cout << f(buf).mysize << std::endl;
}
Anyway, you will need to return an object from f and access it's member by ., not by ::.
But it's more probable that second variant will be slower, because first variant is fully compile-time, but in the second variant compiler may miss the optimization and don't optimize out the run-time creation of foo.
I think you need to add const int Z::mysize; after class declaration.
Why can't you pass literal strings in here? I made it work with a very slight workaround.
template<const char* ptr> struct lols {
lols() : i(ptr) {}
std::string i;
};
class file {
public:
static const char arg[];
};
decltype(file::arg) file::arg = __FILE__;
// Getting the right type declaration for this was irritating, so I C++0xed it.
int main() {
// lols<__FILE__> hi;
// Error: A template argument may not reference a non-external entity
lols<file::arg> hi; // Perfectly legal
std::cout << hi.i;
std::cin.ignore();
std::cin.get();
}
Because this would not be a useful utility. Since they are not of the allowed form of a template argument, it currently does not work.
Let's assume they work. Because they are not required to have the same address for the same value used, you will get different instantiations even though you have the same string literal value in your code.
lols<"A"> n;
// might fail because a different object address is passed as argument!
lols<"A"> n1 = n;
You could write a plugin for your text editor that replaces a string by a comma separated list of character literals and back. With variadic templates, you could "solve" that problem this way, in some way.
It is possible, but the the template argument must have external linkage, which precludes using literal strings and mitigates the utility of doing this.
An example I have is:
template<const char* name, const char* def_value=empty_>
struct env : public std::string
{
env()
{
const char* p = std::getenv(name);
assign(p ? p : def_value);
}
};
extern const char empty_[] = "";
std::string test = env<empty_>();
This is how I do it. Makes a lot more sense to me:
struct MyString { static const std::string val; };
const std::string MyString::val = "this is your string";
template<typename T>
void func()
{
std::cout << T::val << std::endl;
}
void main()
{
func<MyString>();
}
Good question, thought I'd throw my hat into the ring... I guess you can pass pointers to static variables as non-type template arguments. From C++20 it looks like it won't be an issue... Until then, here is some cheap macro to make it work.
template <const char *Name, typename T>
struct TaggedValue {
static constexpr char const *name{Name};
T value;
friend ostream &operator<<(ostream &o, const TaggedValue &a) {
return o << a.name << " = " << a.value;
}
};
#define ST(name, type)\
const char ST_name_##name[]{#name};\
using name = TaggedValue<ST_name_##name,type>;
ST(Foo, int);
ST(Bar, int);
ST(Bax, string);
int main() {
cout << Foo{3} << endl;
cout << Bar{5} << endl;
cout << Bax{"somthing"} << endl;
}
C++20 comment (EDIT)
I've not used c++ much lately, so I'm sorry if this isn't 100% correct. There's a comment about why this wouldn't be an issue in c++20. According to the reference on template_parameters:
A non-type template parameter must have a structural type, which is one of the following types (optionally cv-qualified, the qualifiers are ignored):
...
a floating-point type;
a literal class type with the following properties:
all base classes and non-static data members are public and non-mutable and
the types of all base classes and non-static data members are structural types or (possibly multi-dimensional) array thereof.
This had led me to believe that the following code would work:
struct conststr
{
const char * const p;
template<std::size_t N>
constexpr conststr(const char(&a)[N]) : p(a)/*, sz(N - 1) */{}
};
template<conststr s>
struct A{};
int main(int argc, char **argv) {
A<conststr("foo")> x;
}
(Again, I'm not 100% sure if that's 100% correct). But it doesn't, at least not on my machine with g++ -std=c++2a (g++ --version == g++ (Debian 8.3.0-6) 8.3.0). It doesn't work with double either. This guy gives a much more detailed account of the history here, and there are probably better references, and I could just be completely incorrect.
This works for classes and, IMO, is useful. The implementation is quick and dirty but can easily be made cleaner:
#include <stdio.h>
#include <string.h>
struct TextTag { const char *text; };
template <const TextTag &TRUE, const TextTag &FALSE>
struct TextTaggedBool
{
const char *GetAsText() const { return m_value ? TRUE.text: FALSE.text; }
void SetByText(const char *s) { m_value = !strcmp(s, TRUE.text); }
bool m_value;
};
class Foo
{
public:
void method()
{
m_tbool.SetByText("True!"); printf("%s\n", m_tbool.GetAsText());
m_tbool.SetByText("False!"); printf("%s\n", m_tbool.GetAsText());
m_tbool.m_value = true; printf("%s\n", m_tbool.GetAsText());
m_tbool.m_value = false; printf("%s\n", m_tbool.GetAsText());
}
private:
static constexpr TextTag TrueTag = { "True!" };
static constexpr TextTag FalseTag = { "False!" };
TextTaggedBool<TrueTag, FalseTag> m_tbool;
};
void main() { Foo().method(); }
Output:
True!
False!
True!
False!