Template function is_same in template classes - c++

Why this code produces a false output?
//this-type.cpp
#include <iostream>
#include <type_traits>
using namespace std;
template<typename testype>
class A
{
public:
A()
{
cout << boolalpha;
cout << is_same<decltype(*this), A<int>>::value << endl;
}
};
class B : public A<int>
{
};
int main()
{
B b;
}
Output:
$ g++ -std=c++11 this-type.cpp
$ ./a.out
false
The type of "*this" inside A through B is A< int >, isn't it?

*this is an lvalue of type A, so decltype(*this) will give the reference type A &. Recall that decltype on an lvalue gives the reference type:
cout << is_same<decltype(*this), A<int>>::value << endl;
cout << is_same<decltype(*this), A<int> &>::value << endl;
Output:
false
true

Try:
typedef std::remove_reference<decltype(*this)>::type this_type;
cout << is_same<this_type, A<int>>::value << endl;
and maybe remove_cv in some other contexts (if you don't care about const/volatile) like this:
typedef std::remove_reference<decltype(*this)>::type this_type;
typedef std::remove_cv<this_type>::type no_cv_this_type;
cout << is_same<no_cv_this_type, A<int>>::value << endl;

Are you sure decltype(*this) is A ? You should investigate on that with an ugly cout debug line.

Related

`friend struct std::is_invocable` can't access private members of class it is friend to

I have made struct std::is_invocable be a friend of class D, but it is unable to access the private member of D. This happens with gcc, clang, and MS Visual Studio 2017, so it is not one of MSVC's quirks.
#include <iostream>
#include <string>
#include <type_traits>
#include <iomanip>
#include <cmath>
using std::cin;
using std::cout;
const double PI = 3.1415926535898;
class A
{
public:
A(double xx) : x(xx)
{
s = sin(x);
}
double sinx()
{
return s;
}
private:
double x;
double s;
};
class B
{
public:
double sinx(double x)
{
return sin(x);
}
};
class C
{
public:
static double sinx(double x)
{
return sin(x);
}
};
class D
{
private:
double sinx(double x)
{
return sin(x);
}
public:
template<class T, class... Args>
friend struct std::is_invocable;
};
class E
{
public:
double sinx;
};
int main()
{
std::string s;
A a0(PI/2.);
cout << std::boolalpha;
cout << std::is_invocable<decltype(&A::sinx), A&>::value << "\n";
cout << std::is_invocable<decltype(&B::sinx), B&, const double>::value << "\n";
cout << std::is_invocable<decltype(&B::sinx), const double>::value << "\n";
cout << std::is_invocable<decltype(&C::sinx), const double>::value << "\n";
cout << std::is_invocable<decltype(&D::sinx), D&, const double>::value << "\n"; // shouldn't this compile if
// std::is_invocable is friend?
cout << std::is_invocable<decltype(&E::sinx), E&, const double>::value << "\n";
cout << "Press ENTER to exit.\n";
std::getline(cin, s);
}
The error is:
C2248 "'D::sinx': cannot access private member declared in class 'D'"
Why can't std::is_invocable access D::sinx()?
Why can't std::is_invocable access D::sinx() ?
Because it isn't trying to. main is trying to access D::sinx. Which it can't. Remember: accessibility is about who can use the name of the member. You typed the name "D::sinx" in main. Therefore, it is main that is trying to access the name.
So you're giving access to the wrong thing.

std::visit with passing pointer fails to compile under clang 13

The following code compiles properly under x64 msvc x19.30 and gcc 11 but fails to compile under clang 13.0.1:
"error: cannot pass object of non-trivial type 'std::shared_ptr<std::pair<int, std::variant<Struct1, Struct2, UnsupportedStruct>>>' through variadic function;"
Does anyone know what the problem is?
The following code produces different outputs depending on passing object:
#include <iostream>
#include <variant>
#include <memory>
struct Struct1{};
struct Struct2{};
struct UnsupportedStruct{};
using VarTypeData = std::variant<Struct1, Struct2, UnsupportedStruct>;
using VarType = std::pair<int, VarTypeData>;
namespace
{
void print(Struct1&, std::shared_ptr<VarType> v) {std::cout << v->first << ": Struct1\n";}
void print(Struct2&, std::shared_ptr<VarType> v) {std::cout << v->first << ": Struct2\n";}
void print(...) {std::cout << "no implementation";}
}
int main()
{
VarType data1 = std::make_pair(100, UnsupportedStruct{});
auto pointerData = std::make_shared<VarType>(data1);
std::visit([&pointerData](auto& c) {print(c, pointerData);}, pointerData->second);
std::cout << std::endl;
pointerData->second = Struct1{};
std::visit([&pointerData](auto& c) {print(c, pointerData);}, pointerData->second);
}
This code works fine for clang after dereferencing:
#include <iostream>
#include <variant>
#include <memory>
struct Struct1{};
struct Struct2{};
struct UnsupportedStruct{};
using VarTypeData = std::variant<Struct1, Struct2, UnsupportedStruct>;
using VarType = std::pair<int, VarTypeData>;
namespace
{
void print(const Struct1&, const VarType& v) {std::cout << v.first << ": Struct1\n";}
void print(const Struct2&, const VarType& v) {std::cout << v.first << ": Struct2\n";}
void print(...) {std::cout << "no implementation";}
}
int main()
{
VarType data1 = std::make_pair(100, UnsupportedStruct{});
auto pointerData = std::make_shared<VarType>(data1);
std::visit([&pointerData](auto& c) {print(c, *pointerData);}, pointerData->second);
std::cout << std::endl;
pointerData->second = Struct1{};
std::visit([&pointerData](auto& c) {print(c, *pointerData);}, pointerData->second);
}
thanks to #康桓瑋 for the answer.
this code does not work for clang, because of
void print(...) {std::cout << "no implementation";}
answer: void print(...) is a C function, where variadic actually means the
's parameter. It accepts only trivial types, which
std::shared_ptr is not. So the behavior is undefined or only
conditionally supported
So, the following changes fix the problem:
template<class... Args>
void print(Args&&...) {std::cout << "no implementation";}

C++ function specialization behaves different for plain types and classes

i have this piece of code (http://coliru.stacked-crooked.com/a/ee05a00fc8ab5057):
#include <type_traits>
struct unregistered;
unregistered register_type(...);
template<class T>
constexpr bool is_registered = !std::is_same_v<unregistered, decltype(register_type(std::declval<T>()))>;
template<class T>
struct test_registration
{
static_assert(is_registered<T>, "Type is not registered!");
};
struct foo{};
struct bar{};
void register_type(int);
void register_type(char);
void register_type(void*);
void register_type(foo);
void register_type(foo*);
#include <boost/core/demangle.hpp>
#include <iostream>
int main()
{
std::cout << boost::core::demangle(typeid(test_registration<foo>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<foo*>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<int>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<char>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<void*>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<long>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<bar>).name()) << "\n";
return 0;
}
The compiler generates errors for the calls using int, char, void*, long and bar.
I expect the errors for long and bar.
What I do not understand is:
Why are int, char, and foo treated differently?
Why are void*, and foo* treated differently? (both are ptrs)
I assume the reason has to do with foo beeing class type and int and char beeing plain types.
I would like to know the reason. Is it a compiler bug or is there some passage in the standard explaining this behaviour?
What I am asking is not how I can fix this problem (see link to coliru for a fix).
What I want to know is why it is behaving like this.

How do I use a numeric_cast policy?

So I have my own policy for uint64_t to uint32_t numeric cast
struct MyOverflowHandlerPolicy
{
void operator() ( boost::numeric::range_check_result ) {
std::cout << "MyOverflowHandlerPolicy called" << std::endl;
throw boost::numeric::positive_overflow();
};
} ;
How do I get it to be used by boost::numeric_cast?
In order to use numeric_cast, numeric_cast_traits specialization should defined on each type conversions. These specializations are already defined with default values for the built-in numeric types. It is possible to disable the generation of specializations for built-in types by defining BOOST_NUMERIC_CONVERSION_RELAX_BUILT_IN_CAST_TRAITS (details).
Here is a small running sample.
#include <iostream>
#include <stdexcept>
#define BOOST_NUMERIC_CONVERSION_RELAX_BUILT_IN_CAST_TRAITS
#include <boost/numeric/conversion/cast.hpp>
using namespace std;
struct YourOverflowHandlerPolicy
{
void operator() ( boost::numeric::range_check_result r ) {
cout << "YourOverflowHandlerPolicy called" << endl;
if (r != boost::numeric::cInRange) {
throw logic_error("Not in range!");
}
};
};
namespace boost { namespace numeric {
template <>
struct numeric_cast_traits<uint32_t, uint64_t>
{
typedef YourOverflowHandlerPolicy overflow_policy;
typedef UseInternalRangeChecker range_checking_policy;
typedef Trunc<uint64_t> rounding_policy;
};
template <>
struct numeric_cast_traits<uint64_t, uint32_t>
{
typedef YourOverflowHandlerPolicy overflow_policy;
typedef UseInternalRangeChecker range_checking_policy;
typedef Trunc<uint32_t> rounding_policy;
};
}} //namespace boost::numeric;
int main()
{
try {
cout << boost::numeric_cast<uint32_t>((uint64_t)1) << endl; // OK
cout << boost::numeric_cast<uint32_t>((uint64_t)1<<31) << endl; // OK
cout << boost::numeric_cast<uint32_t>((uint64_t)1<<32) << endl; // Exception
} catch (...) {
cout << "exception" << endl;
}
return 0;
}
Output:
YourOverflowHandlerPolicy called
1
YourOverflowHandlerPolicy called
2147483648
YourOverflowHandlerPolicy called
exception
Note: I have boost release 1.55.0, I don't know the minimum release level to get it compiled but it isn't compiled with 1.46.0. So, please check your boost release and update if necessary.

POD in Visual Studio 2008

The following code
#include <iostream>
#include <new>
#include <cstring>
#include <type_traits>
template<typename T>
void is_pod(char* c)
{
cout << "Type " << c;
if(std::is_pod<T>::value)
::std::cout << " is POD" << endl;
else
::std::cout << " is not!" << endl;
}
#define CHECK_TYPE(ty) ::is_pod<ty>(#ty)
struct POD_Parent{};
struct POD_Child : public POD_Parent{int y;};
struct POD_Child2 {int x; POD_Parent y; POD_Child ssd;};
int main()
{
CHECK_TYPE(POD_Parent);
CHECK_TYPE(POD_Child);
CHECK_TYPE(POD_Child2);
Gives the following results: Which is strange!
Type POD_Parent is POD
Type POD_Child is not!
Type POD_Child2 is POD
How can POD_Child is not POD?! and POD_Child2 is POD?!!
Note that I compiled it using MinGW (using option -std=c++11) and it said that all of them are POD.
According to [MSDN][1] a type that has a base class is not POD so POD_Child is not POD but for POD_Child2 its possibly some mistake of the compiler that ignore base class of ssd