How do user-defined literals play together with digit separator? - c++

I was just modifying an old example of my code by adding a digit separator to a user-defined literal, parsed by a variadic template:
namespace lits {
// helper for 1 arg
template<char C> int bin(); // common
template<> int bin<'1'>() { return 1; } // spec.
template<> int bin<'0'>() { return 0; } // spec.
// helper 2 or more args
template<char C, char D, char... ES>
int bin() {
return bin<C>() << (sizeof...(ES)+1) | bin<D,ES...>() ;
}
// operator"" _bin
template<char...CS> int operator"" _bin()
{ return bin<CS...>(); };
}
int main() {
using namespace lits;
int number = 1000'0000_bin; // <<< I added a ' here
}
Boy, was I surprised when by g++6.2.0 tried to instantiate bin<'\''>. It tried to pass the ' as a char to my template template<char...CS> int operator"" _bin()! I tried it with clang++-3.9 and msvc++-19.00, same complaint, which really makes me sceptical.
I have the feeling that that may not the right behavior. I would have understood it if my literal was in quotes, say "1000'0000"_bin, but this form does not exist for template operator"", right?
Am I to expect the digit separator ' in my template user-literal operators, too, now?
Update 1: in case the ' is ok:
One could use the digit-sep as a sep for all sort of things, say, complex numbers. Would the behavior of `52.84'67.12_i' for 52.84+67.12i be well defined?'
Udpdate 2: As reaction some of the comments. The following compiles:
#include <iostream>
#include <string>
using std::string;
namespace lits {
// helper
template<char C> string sx() { return string{}+C; }
// helper 2 or more args
template<char C, char D, char... ES>
string sx() {
return sx<C>() + sx<D,ES...>();
}
// operator"" _sx
template<char...CS> string operator"" _sx()
{ return sx<CS...>(); };
}
int main() {
using namespace lits;
std::cout << 10000000_sx << '\n';
std::cout << 10'000'000_sx << '\n';
std::cout << 0x00af_sx << '\n';
std::cout << 0x0'c'0'a'f_sx << '\n';
std::cout << 007_sx << '\n';
std::cout << 0b01_sx << '\n';
// the following do not work:
//std::cout << 0b0a8sh3s1_sx << '\n';
//std::cout << "abcde"_sx << '\n';
}
And the output is:
10000000
10'000'000
0x00af
0x0'c'0'a'f
007
0b01
Which means that the template gets all the characters: prefixes and digit separators -- all of them. (g++-6.2.0)
As #krzaq's answer suggests, it seems this is the plan of the Std, so one can rely on it.

As far as I can tell, yes. As explained here, digit separators are legal members of user defined integer literals.
And the template integer literal is defined as:
N4140 § 2.13.8 [lex.ext] / 3
Otherwise (S contains a literal operator template), L is treated
as a call of the form
operator "" X <’c1’, ’c2’, ... ’ck’>()
where n is the source character sequence c1c2...ck. [ Note: The sequence
c1c2...ck can only contain characters
from the basic source character set. —end note ]
There's not a word about removing separators.

As much as I read here the separator is allowed only when you get the literal as a number, not when the operator is a raw literal. That means you will get rid of the separator by the compiler if the operator parameter type is unsigned long long, not if it's one of the raw ones that get C-string or char.

Related

How to use some type specific function (such as .size() for std::string or std::vector and so on) on something of template type?

If possible, how could I use some type-specific function (such as .size() for: std::string or std::vector or ...) in a function with a template type, being sure that when I'll use that type-specific function I'm actually calling it with the correct type as argument? Maybe I'm wrong, and if it is, please explain to me what I have to do.
#include <iostream>
#include <string>
template <typename T>
std::string func(T& number) {
if (typeid(T) == typeid(std::string)) {
unsigned short int size = number.size();// !
return " is a string";
}
else if (typeid(T) == typeid(int)) {
return " is an int";
}
//...
}
int main() {
std::string name = "Anthony";
int age = 8;
std::cout << name /*<< func(name) */<< '\n' << age << func(age) << '.';
return 0;
}
I know that in the code above the line:
unsigned short int size = number.size();//(I need exactly '.size()')
doesn't make any sense (even the whole code doesn't make much sense) considering that I never use that value, but to find the size of the string (when it is a string!) is exactly what I need, and to not post a very long code that would make sense, I'm posting only this to make it give the error I've had when trying to compile, and in order to give you a minimal reproducible example. So please, don't say to me "just delete that line and your code will work").
Instead of if (typeid(T) == typeid(std::string)), use if constexpr (std::is_same_v<T, std::string>). ( Similarly, else if constexpr instead of else if).
Regular if requires both branches to be valid, even if the condition is known at compile-time. if constexpr requires a compile-time condition, but allows the discarded branch to be invalid (only if the error is related to the template argument; every branch has to be theoretically valid for some template argument).
std::is_same_v<T, std::string> is similar to typeid(T) == typeid(std::string), except it counts as a compile-time constant. if constexpr would reject the latter.
If you really need to use a template here, simply specialize the template.
template <typename T>
std::string func(T& number);
template<>
std::string func<std::string>(std::string& number) {
unsigned short int size = number.size();// !
return " is a string";
}
template<>
std::string func<int>(int& number) {
return " is an int";;
}
Usually you using a template you want to avoid using specific implementations for types though. Overloads would be preferrable for a limited set of types using type-specific implementations though.
Since your requirement is not restricted to std::string(as you have mentioned std::vector etc), you can use SFINAE as shown below:
#include <iostream>
#include<typeinfo>
#include<string>
#include<vector>
#include <type_traits>
//make sure that this overload is added to the set when T has a size() member function which is your requirement
template<typename T>
auto func(T const& number) -> decltype((void)(number.size()), std::string())
{
auto size = number.size();
return " is a " + std::string(typeid(number).name());
}
template<typename T>
std::enable_if_t<std::is_fundamental_v<std::remove_reference_t<T>>,std::string> func(T const& number)
{
return " is a " + std::string(typeid(number).name());
}
int main()
{
std::string name = "Anthony";
int age = 8;
double dage = 22.2;
std::cout << name << func(name) << '\n' << age << func(age) << '.'<<"\n"<<dage << func(dage);
//lets test it with vector
std::vector<int> vec= {1,2,3};
std::cout<<"\nvec: "<< func(vec);
return 0;
}
Demo
The output of the above program can be seen here:
Anthony is a NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
8 is a i.
22.2 is a d
vec: is a St6vectorIiSaIiEE

Why is the output of the maximum of two string literals wrong?

Can someone explain, why the output is "C" in this code?
#include <iostream>
using namespace std;
template<class X>
X maximum(X a,X b)
{
if(a > b)
return a;
else
return b;
}
int main() {
cout << maximum("C","D") << endl;
}
Note that in your case the type X will be inferred as const char*, hence you are comparing two const char *s i.e. the addresses of the two string literals.
If you want to get the expected result, use something like the following
cout << maximum("C"s, "D"s) << endl;
To pass std::strings instead of passing the addresses of the string literals.
See string literal operator
Demo
Or use characters instead of using string literals i.e 'C' and 'D' and in that case, X will be inferred as char.
And See Why is "using namespace std;" considered bad practice?
When you use maximum("C","D"), the template parameter is char const*. You end up comparing two pointers. There is no guarantee which pointer will be greater. You have indeterminate behavior.
If you want to compare the string "C" and string "D", you can use:
cout << maximum(std::string("C"), std::string("D")) << endl; // or
cout << maximum("C"s, "D"s) << endl; // or
cout << maximum<std::string>("C", "D");
If you want compare just the characters C and D, you should use
cout << maximum('C', 'D') << endl;
If you want this to work for cstring-literals also, add a specialization.
#include <cstring>
template<class X>
X maximum(X a, X b)
{
return a > b ? a : b;
}
template<>
char const* maximum<char const*>(char const* a, char const* b)
{
return std::strcmp(a, b) > 0 ? a : b;
}

Templates Default Arguments not working in C++

#include <iostream>
template<typename T = char>
T cast(T in){
return in;
}
int main(){
std::cout << cast<>(5) << std::endl;
return 0;
}
Above will print 5 instead of an empty character, as the function is supposed to return a character by default and not an int. What am I ding wrong?
Edit:
Forcing it with std::cout << cast<char>(5) << std::endl; shows an empty character.
The declaration of 5 is an integer by default. This causes 'T' to be overridden with the type int, rather than using your default type. If you really wanted the char of value 5 (which you probably don't), you could specify it as '\x5'.
For the ascii character 5....
int main(){
std::cout << cast('5') << std::endl;
return 0;
}
Default types in templates tend to be useful when it's not easy to determine the template type, e.g. cast from int
template<typename T = char>
T cast(int v){
return T(v);
}
and now this will default to a method that casts an int to a char (rather than a int to int).
std::cout << cast(53) << std::endl;

std::string not updated with = operator

So here's a puzzle for some C++ developers here.
I have a custom String class I'm working with that's supposed to teach me how to get comfortable with classes and a few other C++ features and this class has a value property it uses to keep track of its primitive value (which is a std::string).
But here's a problem, I have define multiple methods for creating an object of this class. 2 of which I understand perfectly:
String stringA = "Hello, World!";
String stringB = String("Hello, World!");
But the last one is a bit tricky as it should be able to work with an infinite set of arguments (theoretically).
String stringC = String("Hello,", ' ', "World!");
But when I access the primitive values of these strings, the last one seems to bug out and return (to the best of my debugging efforts) nothing, garbled text or just part of the arguments given.
stringA.valueOf(); // -> Hello, World!
stringB.valueOf(); // -> Hello, World!
stringC.valueOf(); // -> Hello,
Now, this has been a challenge I've really struggled with especially as a JavaScript developer diving into C++. I know the two languages are fundamentally different, but I figure that logically there should be some features of the former that can somewhat be applied to the latter (such as variadic arguments).
For anyone who can help with this and explain to me what I'm missing (or why my code sucks), you're an absolute champ. Great going for you.
#include <iostream>
/* Let's assume there's a `stringify` function that converts any value to `std::string` */
class String {
private:
std::string value;
public:
template <typename data>
String(data arg) { this -> value += arg; }
template <typename data, typename... argumentsData>
String(data arg, argumentsData... args) {
this -> value += arg;
String(args...);
}
template <typename data>
String operator =(data arg) { return String(this -> value = arg); }
std::string valueOf() const { return this -> value; }
};
int main() {
String stringA = "Hello, World!";
String stringB = String("Hello, World!");
String stringC = String("Hello,", ' ', "World!");
std::cout << "String A: " << stringA.valueOf() << std::endl;
std::cout << "String B: " << stringB.valueOf() << std::endl;
std::cout << "String C: " << stringC.valueOf() << std::endl;
return 0;
}
In your constructor
template <typename data, typename... argumentsData>
String(data arg, argumentsData... args) {
this -> value += arg;
String(args...);
}
This line: String(args...); creates and discards a temporary String, which doesn't affect the state of the original object.
Instead of trying to solve this with recursion, I recommend using fold expressions:
template <typename ...P>
String(const P &... params) // Passing by const reference is purely an optimization.
{
((value += params) , ...);
}

How do we change this function to support multiple arguments?

#include <iostream>
using namespace std;
class SampleClass
{
public:
int test(int ... arguments)
{
cout << arguments[0] << endl; // Access first element in array
return sizeof(arguments);
}
};
int main()
{
SampleClass lol;
cout << lol.test(3, 1, 4, 2, 5, 0) << endl;
return 0;
}
The test function fails due to my limited understanding in C++ semantics. But how can I fix it so that it can access the FIRST element in the arguments lits and then return the size of arguments?
As #Nik pointed out, I could obviously pass in an array, but there is no real fun with that! I am trying to do this just for learning - to see if this is even possible in C++.
Since we're all guessing at what you want, I'll throw in:
template <typename ... Ts>
size_t test(Ts ... arguments) {
auto unused = { 0, ((cout << '[' << arguments << "]\n"), 0)...};
(void)unused;
return sizeof...(arguments);
}
which works with different types of arguments (Live at Coliru). This solution is a bit too "clever" to be readable, though.
The trick here is to build a braced-initializer-list - the {...} stuff - whose elements are initialized by processing the variadic arguments in order. You then convince the compiler that said initializer list isn't used for anything, so the code will be optimized to just generate the desired side effects.
The comma operator in C++ evaluates to the value of the rightmost subexpression. The other subexpressions are evaluated and their values discarded. So ((cout << '[' << arguments << "]\n"), 0) has the effect of dumping some stuff to cout - including one of the variadic parameters - and evaluates to 0. After expanding the pack with the ... that line of code is effectively:
auto unused = { 0, ((cout << '[' << arg0 << "]\n"), 0),
((cout << '[' << arg1 << "]\n"), 0),
((cout << '[' << arg2 << "]\n"), 0) };
The cout junk is evaluated for its side effects and discarded, the whole thing is deduced as a std::initializer_list<int> just as if we had written
auto unused = { 0, 0, 0, 0 };
(The extra zero is there at the beginning to avoid a syntax error if someone calls the function with no arguments at all.)
The (void)unused; line is casting unused to void. It will compile to absolutely nothing, but also will typically tell compilers not to warn us about unused being an unused variable.
try something like this
double test( int num, ... )
{
va_list arguments; // A place to store the list of arguments
double sum = 0;
va_start ( arguments, num ); // Initializing arguments to store all values after num
for ( int x = 0; x < num; x++ ) // Loop until all numbers are added
sum += va_arg ( arguments, double ); // Adds the next value in argument list to sum.
va_end ( arguments ); // Cleans up the list
return sum / num; // Returns the average
}
so youre points are on the wrong side of your parameter list.
i hope this helps and goodluck.
Hm. You are trying to mix two features of C++, variadic-templates and variable-length argument list.
Your code will not compile at all, since you have no templates here and for variable-length argument list declaration should be
int test(int arguments...)
and you can access values from this list with functions from cstdarg header.
With variadic-templates you can do following thing
class Derived
{
public:
template<int... arguments>
int test()
{
int array[] = {arguments...};
return sizeof(array) / sizeof(*array);
}
};
use it like
cout << lol.test<3, 1, 4, 2, 5, 0>() << endl;
I am not quite sure I fully understand your question. If you want access to "the first" argument to the function rather than the template, I think something like this will do it for you, but I may be completely misunderstanding your purpose here:
#include <iostream>
template<typename... Args>
int foo(int arg0, Args... args);
template<>
int foo(int arg0)
{
// here just to catch expansion
std::cout << '[' << arg0 << ']' << std::endl;
return 1;
}
template<typename... Args>
int foo(int arg0, Args... args)
{
foo(arg0);
foo(args...);
return 1 + sizeof...(args);
}
int main()
{
std::cout << foo(1,2,3,4,5) << std::endl;
std::cout << foo(100,200,300) << std::endl;
int a=10, b=20;
std::cout << foo(a,b) << std::endl;
return 0;
}
Output
[1]
[2]
[3]
[4]
[5]
5
[100]
[200]
[300]
3
[10]
[20]
2
You have several options.
1) use an ellipse (only way to have unlimited arg list):
int foo(int a1, ...);
Your code will need to parse the ellipse like printf does. you'll be limited to builtin C types.
2) Use multiple templates:
template<typename T1> int foo(T1 a1);
template<typename T1, typename T2> int foo(T1 a1, T2 a2);
// more templates for more arguments
This method us used, usually up to 10 parameters (10 template functions)
3) Use a function with defaults or illegal values so you'll know which is the last valid argument:
int foo(int a1, int a2 = -1, int a3 = -1, int aN = -1);