我正在使用std::any
的应用程序上工作。
最近我发现,当我用clang编译它时,bad_any_cast
之一上出现了std::any_cast
异常。
我确定我的类型正确。我在typeid(T).name()
中添加了一些cout
转储,以确保插入到std::any
中的类型和我尝试转换为的类型之间没有区别。
我试图编写简单的程序来演示它,但是我无法复制它。
值得一提的是:
我要传递一包std::any
(每个包装内部包含不同类型),只有一个包装有问题(其std::map<ENUM, int>
)。
当我切换到boost::any
时(或者如果我使用gcc构建应用程序),问题消失了。
我已经深入研究std::any_cast
的实现,但失败了:
template<typename _Tp>
void* __any_caster(const any* __any)
{
if constexpr (is_copy_constructible_v<decay_t<_Tp>>)
{
if (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage)
{
any::_Arg __arg;
__any->_M_manager(any::_Op_access, __any, &__arg);
return __arg._M_obj;
}
}
return nullptr;
}
第二个if (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage)
语句未通过。
在我看来,同一个any::_Manager<decay_t<_Tp>>::_S_manage
有_Tp
的一些实例(可能是由我的应用程序由几个模块组成的),但是我无法在一个简单的示例中重现它。 / p>
你们对我有什么建议或提示吗?
编辑
受评论和答案的启发,我创建了一个示例,弄乱了默认可见性(这也是我在我的应用程序中所做的事情),这似乎是问题的根源。
文件:
lib.cpp
#include <any>
#include <map>
enum class D
{
a,
b,
c,
d,
e,
};
int read(const std::any& a)
{
auto map = std::any_cast<std::map<D, int>>(a);
return map.begin()->second;
}
std::any create()
{
std::map<D, int> b = { {D::c, 5} };
std::any a(b);
return a;
}
lib2.cpp
#include <any>
#include <map>
std::any create();
int read(const std::any& a);
__attribute__ ((visibility("default"))) std::any build_bar2()
{
return create();
}
__attribute__ ((visibility("default"))) int read_foo2(const std::any& a)
{
return read(a);
}
lib3.cpp
#include <any>
#include <map>
int read(const std::any &);
std::any create();
__attribute__ ((visibility("default"))) int read_foo3(const std::any& a)
{
return read(a);
}
__attribute__ ((visibility("default"))) std::any build_bar3()
{
return create();
}
main.cpp
#include <any>
int read_foo2(const std::any& a);
std::any build_bar2();
int read_foo3(const std::any& a);
std::any build_bar3();
int main()
{
const std::any& a = build_bar3();
int av = read_foo2(a);
const std::any& b = build_bar2();
int bv = read_foo3(a);
return av == bv? 1: 0;
}
制作文件
CPP=clang++
all: main
lib.o: lib.cpp
$(CPP) -std=c++17 -fvisibility=hidden -g -O0 -fPIC -c lib.cpp -o lib.o
lib2.so: lib2.cpp lib.o
$(CPP) -std=c++17 -fvisibility=hidden -g -O0 -fPIC -shared lib2.cpp lib.o -o lib2.so
lib3.so: lib3.cpp lib.o
$(CPP) -std=c++17 -fvisibility=hidden -g -O0 -fPIC -shared lib3.cpp lib.o -o lib3.so
main: main.cpp lib3.so lib2.so
$(CPP) -std=c++17 -fvisibility=hidden -g -O0 main.cpp ./lib2.so ./lib3.so -o main
clean:
rm -f ./lib.o ./lib2.so ./lib3.so ./main
因此,我有2个共享库,这些共享库链接了负责std::any
创建和转换的公共静态库。在静态lib的一个站点中创建std::any
并在另一个静态目录中强制转换时,会出现异常。
答案 0 :(得分:3)
如果您使用的是Linux或OS X这样的Unix,则C ++类型ID是由指向类型信息的指针处理的,而不是名称字符串匹配项。
这意味着,如果您拥有共享库或具有“相同”类型的静态库,但是它们具有自己的单独副本,则类型信息将不匹配。
这可能取决于您的情况。
我相信您必须在any
中定义一个使用默认可见性声明的公共共享库中的类型。那应该使所有其他共享库都使用该副本,而不是其静态库中的隐藏副本。