- Variadic template parameters as const references - 6 Updates
- Is this code legal or not? Mr Flibble Is Very Cross - 4 Updates
- Replacing an element in a vector - 7 Updates
- Replacing an element in a vector - 1 Update
Juha Nieminen <nospam@thanks.invalid>: Apr 12 06:38AM Suppose I wanted to write a variadic template function but so that the function takes all of its parameters as const references (rather than universal references). No problem, right? template<typename... Params_t> void foo(const Params_t&... params); The problem with this is that this effetively "removes const" from the supplied types. Or, rather, Params_t expands to the non-const versions of the input types. So, for example, calling it with something like: foo("hello"); will make Params_t be a "char*", not a "const char*". This isn't a problem as long as "Params_t" itself isn't used inside the function. It can become a problem if it is being used. For example something like std::tuple<Params_t...> values; becomes problematic because it expands to std::tuple<char*> values; and you cannot assign a const char* to that. Is there a way to take all parameters to a variadic template function as const references *without* removing the "constness" of the types in the parameter pack? |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Apr 12 11:51AM +0100 > something like: > foo("hello"); > will make Params_t be a "char*", not a "const char*". Won't it make it char [6]? When taking a reference, "hello" has type const char [6]. > becomes problematic because it expands to > std::tuple<char*> values; > and you cannot assign a const char* to that. I think it is equivalent to std::tuple<char [6]> and you can't assign arrays so the const issue is not the main issue. You can call foo((const char *)"hello") and then, in foo, assign std::get<0>(values) = "goodbye"; but that's really clumsy. I don't know how you can make a string literal convert to a pointer when you have a reference parameter pack. > Is there a way to take all parameters to a variadic template function > as const references *without* removing the "constness" of the types > in the parameter pack? I don't think the constness is being removed. -- Ben. |
Juha Nieminen <nospam@thanks.invalid>: Apr 12 03:20PM >> will make Params_t be a "char*", not a "const char*". > Won't it make it char [6]? When taking a reference, "hello" has type > const char [6]. You may be right. However, the problem I'm referring to also exhibits itself with things like: const char* str = "hello"; foo(str); Params_t will expand to char*, not const char*, so it becomes problematic if I would want to use Params_t inside the function. The "universal reference" syntax kind of fixes *that* particular problem, but introduces others (in a way, it's "too good" for this purpose). If I really wanted to take all parameters by const reference, not by universal reference, it seems difficult. |
Marcel Mueller <news.5.maazl@spamgourmet.org>: Apr 12 07:52PM +0200 Am 12.04.20 um 17:20 schrieb Juha Nieminen: > foo(str); > Params_t will expand to char*, not const char*, so it becomes problematic > if I would want to use Params_t inside the function. I see no problem here. Either you want catch const T& /and/ T&. In this case remove the cont from the function definition. Or your function should only work with const references. In this case write const Params_t inside your class, not only in the functions parameter list. E.g.: std::tuple<const Params_t...> values; Marcel |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 12 10:22PM +0200 On 12.04.2020 17:20, Juha Nieminen wrote: > foo(str); > Params_t will expand to char*, not const char*, so it becomes problematic > if I would want to use Params_t inside the function. Since it's a reference it won't remove the pointee's `const`. It does remove the item `const`-ness for an array type, because a const raw array of T is a raw array of const T. --------------------------------------------------------------- #include <iostream> #include <typeinfo> using namespace std; template< class... Params_t > void foo( const Params_t&... ) { ((cout << typeid( Params_t ).name() << endl), ...); } auto main() -> int { const char* s = "Hello"; const auto& t = "Hello"; foo( s, t ); } --------------------------------------------------------------- Result with Visual C++ 2019: char const * __ptr64 char [6] > but introduces others (in a way, it's "too good" for this purpose). > If I really wanted to take all parameters by const reference, not by > universal reference, it seems difficult. In short, there is a problem, but not the one you think. - Alf |
Ben Bacarisse <ben.usenet@bsb.me.uk>: Apr 12 09:51PM +0100 > foo(str); > Params_t will expand to char*, not const char*, so it becomes problematic > if I would want to use Params_t inside the function. Hmm... Not as far as I can tell. Can you give and short example. If I write: #include <tuple> template<typename... Params_t> void foo(const Params_t&...) { std::tuple<Params_t...> t; std::get<0>(t) = "text"; } int main() { const char *s; foo(s); char *t; foo(t); } the second foo causes problems but not the first. > but introduces others (in a way, it's "too good" for this purpose). > If I really wanted to take all parameters by const reference, not by > universal reference, it seems difficult. I am not sure I follow, sorry. -- Ben. |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Apr 12 05:17AM +0100 Hi! Flibble is currently very cross due to the following code: #include <cstdint> #include <type_traits> #include <variant> #include <iostream> template <typename T> T foo(const std::variant<int64_t, double, std::string>& v) { T result; std::visit([&result](auto&& a) { typedef std::decay_t<decltype(a)> vt; if constexpr (std::is_same_v<vt, double>) result = static_cast<T>(a); else if constexpr (std::is_same_v<vt, int64_t>) result = static_cast<T>(a); else if constexpr (std::is_same_v<vt, std::string> && std::is_class_v<T>) result = T::from_string(a); // Pfft else throw std::logic_error("wibble"); }, v); return result; } int main() { std::cout << foo<double>(int64_t{}); } Is the line marked "Pfft" legal or not? g++ (Wandbox HEAD) thinks it is whilst clang++ (Wandbox HEAD) thinks it is illegal. I would expect the constexpr if statement to not be considered if T isn't of class type. https://wandbox.org/permlink/IcnMGxGSdAkBb2iP /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 12 05:30PM +0200 On 12.04.2020 06:17, Mr Flibble wrote: > whilst clang++ (Wandbox HEAD) thinks it is illegal. I would expect the > constexpr if statement to not be considered if T isn't of class type. > https://wandbox.org/permlink/IcnMGxGSdAkBb2iP I agree with your reasoning. It's syntactically valid so should be OK when that branch isn't taken. Since partial specialization of functions isn't supported one workaround is to define a class template with a static function, specialize it for each case, and invoke the static function from a free function template. In passing, why throw a `std::logic_error`? If the logic is astray, then best to terminate? - Alf |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Apr 12 04:42PM +0100 On 12/04/2020 16:30, Alf P. Steinbach wrote: >> https://wandbox.org/permlink/IcnMGxGSdAkBb2iP > I agree with your reasoning. It's syntactically valid so should be OK when that branch isn't taken. > Since partial specialization of functions isn't supported one workaround is to define a class template with a static function, specialize it for each case, and invoke the static function from a free function template. Rather than a workaround I am going to raise a clang++ defect report and leave it as-is because that method is the cleanest in my opinion (the whole point of if constexpr is so you don't have to specialize templates). > In passing, why throw a `std::logic_error`? If the logic is astray, then best to terminate? I only catch std::logic_error exceptions to log and then re-throw so the program will terminate. /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Apr 12 09:06PM +0100 On 12/04/2020 16:30, Alf P. Steinbach wrote: > I agree with your reasoning. It's syntactically valid so should be OK when that branch isn't taken. > Since partial specialization of functions isn't supported one workaround is to define a class template with a static function, specialize it for each case, and invoke the static function from a free function template. > In passing, why throw a `std::logic_error`? If the logic is astray, then best to terminate? I have raised a clang++ defect report: https://bugs.llvm.org/show_bug.cgi?id=45506 /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
jacobnavia <jacob@jacob.remcomp.fr>: Apr 12 10:15AM +0200 How do you replace an element at, say, position 4? You have to erase the element and then insert a new one? Thanks in advance |
Barry Schwarz <schwarzb@delq.com>: Apr 12 01:36AM -0700 On Sun, 12 Apr 2020 10:15:11 +0200, jacobnavia >How do you replace an element at, say, position 4? Does vec[4] = value; not do what you want? >You have to erase the element and then insert a new one? Why would you think that? -- Remove del for email |
Juha Nieminen <nospam@thanks.invalid>: Apr 12 09:21AM > Does > vec[4] = value; > not do what you want? More like vec[3] = value; (Although, admittedly, "position 4" is ambiguous, as it could mean either one.) |
jacobnavia <jacob@jacob.remcomp.fr>: Apr 12 11:43AM +0200 Le 12/04/2020 à 11:21, Juha Nieminen a écrit : > More like vec[3] = value; > (Although, admittedly, "position 4" is ambiguous, as it > could mean either one.) OK, I suppose that any destructors for the old element are called of course. Thanks for your answers and sorry for this stupid question... |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 12 11:47AM On Sun, 2020-04-12, jacobnavia wrote: >> could mean either one.) > OK, I suppose that any destructors for the old element are called of > course. To be pedantic, no object is destroyed: operator= () is invoked for the element. But the bottom line is it's a safe thing to do, just like it would be e.g. with an array of int in C. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
Juha Nieminen <nospam@thanks.invalid>: Apr 12 03:22PM > OK, I suppose that any destructors for the old element are called of course. Whatever the assignment operator for the type in question does is done. In practice it just works. |
Real Troll <real.troll@trolls.com>: Apr 12 02:45PM -0400 On 12/04/2020 09:15, jacobnavia wrote: > How do you replace an element at, say, position 4? > You have to erase the element and then insert a new one? Something like this would work: > myvector.erase(myvector.begin() + 3); > myvector.insert(myvector.begin() + 3, 60); The first line erases the item; The second line inserts the number 60 in the 4th place. |
ram@zedat.fu-berlin.de (Stefan Ram): Apr 12 05:52PM >How do you replace an element at, say, position 4? Some responders already gave the best answer when they suggested to use an assignment. >You have to erase the element and then insert a new one? It would indeed be possible to take your suggestion literally. First, destroying the object in place and then using a placement new. For example, Lisa Lippincott does something like this for illustration purposes in her talk "What is the basic interface?", Lisa: |void |implementation foo( int& x ) | { | x.~int(); | new( &x )const int( 2 ); | } . But usually, such an approach would be necessary in only one per thousand cases or less in practice. |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment