Tuple Traits Explanation - c++

#include <array>
#include <iostream>
#include <string_view>
#include <tuple>
#include <type_traits>
namespace a::b::c
{
inline constexpr std::string_view str{ "hello" };
}
template <class... T>
std::tuple<std::size_t, std::common_type_t<T...>> sum(T... args)
{
return { sizeof...(T), (args + ...) };
}
int main()
{
auto [iNumbers, iSum]{ sum(1, 2, 3) };
std::cout << a::b::c::str << ' ' << iNumbers << ' ' << iSum << '\n';
std::array arr{ 1, 2, 3 };
std::cout << std::size(arr) << '\n';
return 0;
}
When I run this program I'm getting this error.
1>D:\Programming\CPP\LearningCPP\LearningCPP.cpp(28,9): error C2440:
'return': cannot convert from 'initializer list' to
'std::tuple<size_t,std::common_type<int,int,int>>'
1>D:\Programming\CPP\LearningCPP\LearningCPP.cpp(27,1): message : No
constructor could take the source type, or constructor overload
resolution was ambiguous
1>D:\Programming\CPP\LearningCPP\LearningCPP.cpp(33): message : see
reference to function template instantiation
'std::tuple<size_t,std::common_type<int,int,int>>
sum<int,int,int>(int,int,int)' being compiled
This is source code which is used in Learncpp.com . Actually I was having difficult understanding and I'm getting these errors, I have changed the compiler version to c++17 still getting these errors and the code can someone help me by explain the code thanks

Related

Usage of concepts with non-type template parameter packs in boolean contexts

In C++20, I defined a concept AllIntegral with a non-type template parameter pack auto... T_values.
Whilst, GCC 10.1.0 accepts its usage in some contexts, it refuses to compile its usage in others, particularly in an
if statement. The associated error message says 'AllIntegral' does not constrain a type.
My code looks like this:
#include <concepts>
#include <ios>
#include <iostream>
template<auto... T_values>
concept AllIntegral = (std::integral<decltype(T_values)> && ...);
int main()
{
std::cout << std::boolalpha << AllIntegral<1, 2> << '\n'; // compiles and prints "true"
if (AllIntegral<1, 2>) std::cout << "true" << '\n'; // does not compile
std::cout.flush();
}
This is the compiler output:
main.cpp: In function ‘int main()’:
main.cpp:11:9: error: ‘AllIntegral’ does not constrain a type
11 | if (AllIntegral<1, 2>) std::cout << "true" << '\n';
| ^~~~~~~~~~~~~~~~~
main.cpp:6:9: note: concept defined here
6 | concept AllIntegral = (std::integral<decltype(T_values)> && ...);
What's the reason for this error? Why is my concept not usable in a boolean context?

C++ template specialization for pointer?

I read book < C++ Templates - the Complete Guide > and learned template specialization for pointer. (maybe I misunderstand this part of the book)
(1) Here's my simple template:
#include <iostream>
template<typename T>
void Function(const T& a)
{
std::cout << "Function<T>: " << a << std::endl;
}
template<typename T>
void Function<T*>(const T* a)
{
std::cout << "Function<T*>: " << a << std::endl;
}
int main(void)
{
Function(1);
Function(1.2);
Function("hello");
Function((void*)0x25);
return 0;
}
I use ubuntu16.04 x64, g++ 5.3, the compiler report:
$ g++ main.cpp -o main.exe
main.cpp:10:29: error: non-type partial specialization ‘Function<T*>’ is not allowed
void Function<T*>(const T* a)
(2) but this code is correct:
#include <iostream>
template<typename T>
void Function(const T& a)
{
std::cout << "Function<T>: " << a << std::endl;
}
int main(void)
{
Function(1);
Function(1.2);
Function("hello");
Function((void*)0x25);
return 0;
}
result shows:
$ g++ main.cpp -o main.exe
$ ./main.exe
Function<T>: 1
Function<T>: 1.2
Function<T>: hello
Function<T>: 0x25
My question is: Is the book about pointer specialization is wrong ? Or I mis understand the meaning of this part in the book ? Or something else ?
Update about pointer specialization in class.
(3) template class with pointer specialization:
#include <iostream>
template<typename T>
struct Base {
T member;
Base(const T& a)
: member(a)
{
}
void hello()
{
std::cout << member << std::endl;
}
};
template<typename T>
struct Base<T*> {
T* member;
Base(T* a)
: member(a)
{
}
void hello()
{
std::cout << member << std::endl;
}
};
int main(void)
{
Base<int> b1(12);
Base<double> b2(2.4);
Base<char*> b3("hello");
Base<void*> b4((void*)0x25);
b1.hello();
b2.hello();
b3.hello();
b4.hello();
return 0;
}
this code is correct with one warning:
$ g++ main.cpp -o main.exe
main.cpp: In function ‘int main()’:
main.cpp:37:27: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Base<char*> b3("hello");
^
$ ./main.exe
12
2.4
hello
0x25
(4) template class without pointer specialization:
#include <iostream>
template<typename T>
struct Base {
T member;
Base(const T& a)
: member(a)
{
}
void hello()
{
std::cout << member << std::endl;
}
};
int main(void)
{
Base<int> b1(12);
Base<double> b2(2.4);
Base<char*> b3("hello");
Base<void*> b4((void*)0x25);
b1.hello();
b2.hello();
b3.hello();
b4.hello();
return 0;
}
result is the same:
$ g++ main.cpp -o main.exe
main.cpp: In function ‘int main()’:
main.cpp:39:27: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Base<char*> b3("hello");
^
$ ./main.exe
12
2.4
hello
0x25
Does this means pointer specialization is needless ?
Or maybe this feature behave differently on different compiler ?
as you've been already told, partial specialization of function templates are not allowed. You can use std::enable_if for this:
template <typename T, typename std::enable_if_t<!std::is_pointer<T>::value>* = 0>
void func(T val) { std::cout << val << std::endl; }
template <typename T, typename std::enable_if_t<std::is_pointer<T>::value>* = 0>
void func(T val) { func(*val); }
If you are looking for simpler syntax, wait for concepts
The error message told you what is wrong:
non-type partial specialization ‘Function<T*>’ is not allowed
You can only partially specialize types (classes). You've tried to partially specialize a function. Functions are not types; you can only fully specialize them.
Two problems:
You are not allowed to partially specialise a function.
The behaviour of (void*)0x25 is undefined. With the exception of nullptr, you are not allowed to set a pointer to memory you don't own, with the exception of one past the final element of an array and one past the address of a scalar.

g++ and clang++ different behaviour with SFINAE and SFINAE failure

A couple of questions for C++11 experts.
I'm fighting with SFINAE and I came across a strange case in which g++ (4.9.2), and clang++ (3.5.0) behave differently.
I have prepared the following sample code. I'm sorry but I'm unable to do it significantly more concise.
#include <string>
#include <iostream>
#include <typeinfo>
#include <type_traits>
template <typename X>
class foo
{
private:
template <typename R>
using enableIfIsInt
= typename std::enable_if<std::is_same<X, int>::value, R>::type;
public:
foo ()
{ }
template <typename R = void>
enableIfIsInt<R> bar ()
{ std::cout << "bar: is int\n"; }
void bar ()
{
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
<< typeid(enableIfIsInt<void>).name() << "}\n";
}
};
int main ()
{
foo<long> fl;
foo<int> fi;
fl.bar();
fi.bar();
return 0;
}
My idea was to create a template foo<X> class that (via SFINAE) can define a method in one or in another way depending on the X template argument.
The program compile well with g++ 4.9.2 but clang++ 3.5.0 give the following error
test.cpp:13:36: error: no type named 'type' in
'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable
this declaration
= typename std::enable_if<std::is_same<X, int>::value, R>::type;
^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:26:23: note: in instantiation of template type
alias 'enableIfIsInt' requested here
<< typeid(enableIfIsInt<void>).name() << "}\n";
^
test.cpp:36:7: note: in instantiation of member function
'foo<long>::bar' requested here
fl.bar();
^
1 error generated.
I suppose that is right clang++ but my first question to C++11 experts is: who right? g++ or clang++?
About the g++ produced program output, it's the following
bar: isn't int; is [i]{v}
so g++ seems to ignore the fl.bar(); instruction.
Now a little change: i modify the second version of foo<X>::bar() in this way
void bar ()
{ std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n"; }
deleting the std::enable_if inside the function abomination. Now both g++ and clang++ are compiling without problems and the output, for both compiled versions of the program, is
bar: isn't int; is [l]
bar: isn't int; is [i]
So, my second question is: what I'm doing wrong? Why, in the int case, I don't obtain the "is int" version of foo<X>::bar()?
Be patient with me if I'm doing some foolish: I'm trying to learn C++11.
And sorry for my bad English.
clang's error isn't coming from the substitution failure. It's coming from here:
void bar ()
{
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
<< typeid(enableIfIsInt<void>).name() << "}\n"; // <==
}
enableIfIsInt<void> isn't in the immediate context, that's a hard failure for X is not int. You simply can't use that expression in that context.
Once you remove that - the non-template bar() is always called. That's because both functions are equivalent matches and non-templates are preferred to templates in overload resolution.
So the real solution is to use tag-dispatching:
void bar() { bar(std::is_same<X, int>{}); }
void bar(std::true_type ) {
std::cout << "bar: is int\n";
}
void bar(std::false_type ) {
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n";
}
with which both compilers happily yield:
bar: isn't int; is [l]
bar: is int

constexpr char array with GCC and clang

Consider the following code:
#include <cstddef>
#include <iostream>
#include <stdexcept>
class const_string {
public:
template <std::size_t sz>
constexpr const_string(const char (&str)[sz]): p_(str) {}
constexpr char operator[](std::size_t i) const { return p_[i]; }
private:
const char* p_;
};
template <char c>
void Print() { std::cout << c << '\n'; }
int main() {
constexpr char str[] = "Hello World";
Print<const_string(str)[0]>();
}
It compiles fine with clang, while GCC gives the following error message:
in constexpr expansion of 'const_string((* & str)).const_string::operator[](0ul)'
error: '(const char*)(& str)' is not a constant expression
However, if I change Print<const_string(str)[0]>(); to Print<const_string("Hello World")[0]>();. Both clang and GCC compile fine.
What is going on here? Which compiler is correct according to the standard?
It's a bug and appears to compile on gcc 5 as shown here.

Why does the order of template parameters matter to the MS C++ compiler in this example?

The following code compiles fine in GCC but in Visual Studio it results in
error C2782: 'bool contains(const T &,const std::initializer_list<T2>
&)' : template parameter 'T' is ambiguous see declaration of
'contains' could be 'const wchar_t *' or 'std::wstring'
It does however compile and work if the order of the template parameters is given as
template<typename T2, typename T>
Is this a compiler bug?
#include <string>
#include <iostream>
#include <set>
#include <initializer_list>
#include <algorithm>
template<typename T, typename T2>
bool contains(T const& value, std::initializer_list<T2> const& set)
{
return std::find(std::begin(set), std::end(set), value) != std::end(set);
}
int main(void)
{
std::set<std::wstring> values = { L"bar", L"not" };
for (std::wstring val : values) {
std::wcout << "\"" << val << "\" ";
if (contains(val, { L"foo", L"bar", L"baz", L"doom" })) {
std::wcout << "found" << std::endl;
}
else {
std::wcout << "not found" << std::endl;
}
}
}
Edit: I have created a bugreport: https://connect.microsoft.com/VisualStudio/feedbackdetail/view/982338/template-parameter-order-matters
I remember that VS has a bug where they would do double-deduction in certain scenarios, and I think that's what's happening here. Clang also compiles it both ways, so since clang + gcc agree, it's likely a VS bug.
I had a similar problem which was resolved by switching to the latest VS Pro version. I think this bug was addressed in the latest VS pro version as I remember seeing it in a change-log at some point.