boost::any test code compiles with Sun CC but not g++ - c++

The following noddy test code:
#include <iostream>
#include <list>
#include <boost/any.hpp>
#include <boost/foreach.hpp>
#include <typeinfo.h>
using boost::any_cast;
using std::cout;
using std::cerr;
typedef std::list<boost::any> many;
template <typename T>
inline bool is_any(const boost::any& op)
{
return (op.type() == typeid(T));
}
int main()
{
many theStrangeList;
theStrangeList.push_back("Can you really...");
theStrangeList.push_back(std::string ("do random types in 1 container?"));
theStrangeList.push_back(6.359);
theStrangeList.push_back(7);
BOOST_FOREACH(boost::any a, theStrangeList)
{
try
{
if (is_any<const char*>(a))
{
cout << any_cast<const char*>(a) << '\n';
}
else if (is_any<std::string>(a))
{
cout << any_cast<std::string>(a) << '\n';
}
else if (is_any<double>(a))
{
cout << "double = " << any_cast<double>(a) << '\n';
}
}
catch (const boost::bad_any_cast& e)
{
cerr << e.what();
cerr << "\n";
}
}
return 0;
}
Compiles and works fine using Sun's CC compiler and default settings.
However when using g++ I get the following :
$ g++ -I$BOOST_ROOT -o myany myany.cpp
myany.cpp:5:22: typeinfo.h: No such file or directory
/ilx/boost_1_41_0/boost/any.hpp: In constructor `boost::any::holder<ValueType>::holder(const ValueType&) [with ValueType = char[18]]':
/ilx/boost_1_41_0/boost/any.hpp:47: instantiated from `boost::any::any(const ValueType&) [with ValueType = char[18]]'
myany.cpp:21: instantiated from here
/ilx/boost_1_41_0/boost/any.hpp:122: error: ISO C++ forbids assignment of arrays
This is g++ version 3.4.3, so it might be different on a 4.x version, I'll try it later. Is this the reason why there isn't a 'is_any' template included with boost any, or is it a compiler bug?
I get the same result if I remove the template, as you would expect with an inlined function.
(related question)

For the first error try
#include <typeinfo>
not
#include <typeinfo.h>

Seems I only answered the second part of the question, so here I go with the first part as well:
Is this the reason why there isn't a 'is_any' template included with boost any?
There are no actual need to is_any, do the following instead:
if (const std::string* s = boost::any_cast<std::string>(&a))
{
std::cout << "string = " << *s << '\n';
}
else if (const double* d = boost::any_cast<double>(&a))
{
std::cout << "double = " << *d << '\n';
}
But this isn't extensible, prefer using boost::variant instead.
Is it a compiler bug?
It is a compiler bug in Sun CC. gcc is correct, the type of "Can you really..." is char[18], which doesn't satisfy the requirements of boost::any:
A ValueType is CopyConstructible.
A ValueType is optionally Assignable. The strong exception-safety guarantee is required for all forms of assignment.
The destructor for a ValueType upholds the no-throw exception-safety guarantee.

Related

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.

Meaning of phrase "constructors do not have names" in the C++ Standard

While trying to understand the phrase "constructors do not have names" in the C++ Standard, it seems like I found an error in clang. Could someone confirm this?
VS2015 and gcc rejects this code, and I think they it are is correct. At least, this is the impression I get from §12.1[class.ctor]/2 in N4140:
#include <iostream>
class A {
public:
A() { std::cout << "A()" << '\n'; }
};
int main()
{
A::A();
}
§12.1[class.ctor]/2 in N4140:
A constructor is used to initialize objects of its class type. Because
constructors do not have names, they are never found during name
lookup; ...
With the expression A::A(); above, clang finds the constructor by name lookup, when it should find the type name A instead. See live example.
Your intuition is correct. This is a known Clang bug 13403 with status NEW.
I agree that this should not compile.
It's actually more bizzare than you thought. Try this:
#include <iostream>
#include <string>
class A {
public:
A() {
std::cout << "A() " << this << '\n';
}
void foo() {
std::cout << _message << std::endl;
}
std::string _message = "hello";
};
int main()
{
A::A().foo();
}
example output:
A() 0x7fff5cd105f8
hello
It looks to me as if an un-named A is being implicitly created.

Capture this in lambda attribute inside a templated class vs not-templated class

I have succeeded writing a class like this one, capturing this in a lambda defined as non-static attribute of said class:
#include <memory>
#include <iostream>
#include <functional>
struct S
{
S()
{
std::cout << "S::S()[" << this << "]" << std::endl;
}
std::string y_{"hi mate"};
int x_;
std::function<void(int*)> del_{[this](int *ptr)
{
std::cout << "Deleting ptr[" << ptr << "] this[" << this << "] this->y_[" << this->y_ << "]" << std::endl;
}};
std::unique_ptr<decltype(x_), decltype(del_)> unique_{&x_, del_};
};
int main()
{
S s;
}
This compiles and seems to run just fine.
However, with a templated class, it doesn't work anymore:
#include <memory>
#include <iostream>
#include <functional>
template <typename>
struct S
{
S()
{
std::cout << "S::S()[" << this << "]" << std::endl;
}
std::string y_{"hi mate"};
int x_;
std::function<void(int*)> del_{[this](int *ptr)
{
std::cout << "Deleting ptr[" << ptr << "] this[" << this << "] this->y_[" << this->y_ << "]" << std::endl;
}};
std::unique_ptr<decltype(x_), decltype(del_)> unique_{&x_, del_};
};
int main()
{
S<int> s;
}
$> g++ -std=c++1y custom_deleter_template.cpp
~/test custom_deleter_template.cpp: In instantiation of ‘struct
S::’: custom_deleter_template.cpp:9:3: required
from ‘S< >::S() [with
= int]’ custom_deleter_template.cpp:24:10:
required from here custom_deleter_template.cpp:15:35: internal
compiler error: in tsubst_copy, at cp/pt.c:12569
std::function del_{[this](int *ptr)
^ Please submit a full bug report, with preprocessed source if appropriate. See
for instructions.
Preprocessed source stored into /tmp/pyro/ccxfNspM.out file, please
attach this to your bugreport.
Before filing a bugreport (which I can't do, they blocked account creation), is it normal that it does not compile, based on what the standard says?
Compiler is g++ (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2, used flag -std=c++1y. Same thing happens with flag -std=c++11.
This is indeed a bug in GCC, which is already being tracked.
It seems to affect 4.8 and 4.9. As pointed out in the comments this particular example works fine for 4.7 and 5.0. You can see that for yourself here and play with the different versions of gcc.
However this reduced version of your code with no external dependency still crashes with 5.0:
template <typename>
struct S {
int f{[this](){return 42;}()};
};
int main(){
return S<int>{}.f; // should return 42
}
I would suggest that you wait for the bug I referenced to be fixed before using your code, or switch to another compiler ;).

How do I write template code that handles type conversion for strings?

I was trying to make a simple function that allowed checking if a string was in a given list.
Here is some demo code:
#include <string>
#include <iostream>
#include <set>
#include <initializer_list>
template<typename T2, typename T>
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;
}
}
}
As you can see I am trying to check if a std::wstring is in a list of const wchar_t*consts.
This compiles with the MS compiler (and seems to work) but GCC complains that no types to make it work can be derived. Interestingly it also doesn't compile with the MS compiler anymore if I switch the order of the template parameters so the 6th line reads:
template<typename T, typename T2>
In that case the compiler says T is ambiguous.
I've tried a few variations like using only one template parameter but then I can't call it with strings and pointers anymore.
How do I do this - if possible - properly?
Your code compiles in GCC 4.8.1 with the addition of:
#include <algorithm>
std::find is declared in <algorithm>. The C++ Standard Library that ships with MSVC often brings in seemingly unnecessary headers. I'm betting is tagging along with <set> or <initializer_list>.
A working example can be found here.
You're grabbing a wrong overload of find (best effort - the compiler can't find the intended one), you need to include
#include <algorithm>
This is also true for gcc 4.9.0