- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我们在 GCC 中看到了以下代码示例中的一些奇怪行为。奇怪的行为是 GCC 6.3.0 中的 ODR 违规,类型定义在两个单独的翻译单元中。可能与递归类型定义或类型不完整有关。
我们不确定我们的代码是否有效,或者我们是否以递归定义类型的方式依赖于未定义的行为。请查看类变体动态类模板是如何在两个单独的 cpp 文件中定义和实例化的。
动态测试.h:
#pragma once
#include <algorithm>
#include <type_traits>
namespace dynamic
{
template <class T>
void erasure_destroy( const void *p )
{
reinterpret_cast<const T*>( p )->~T();
}
template <class T>
void erasure_copy( void *pDest, const void *pSrc )
{
::new( pDest ) T( *reinterpret_cast<const T*>( pSrc ) );
}
template <class T>
struct TypeArg {};
struct ErasureFuncs
{
template <class T = ErasureFuncs>
ErasureFuncs( TypeArg<T> t = TypeArg<T>() ) :
pDestroy( &erasure_destroy<T> ),
pCopy( &erasure_copy<T> )
{
(void)t;
}
std::add_pointer_t<void( const void* )> pDestroy;
std::add_pointer_t<void( void*, const void* )> pCopy;
};
enum class TypeValue
{
Null,
Number,
Vector
};
template <typename T>
using unqual = std::remove_cv_t<std::remove_reference_t<T>>;
template <class Base, class Derived>
using disable_if_same_or_derived = std::enable_if_t<!std::is_base_of<Base, unqual<Derived>>::value>;
template <template <class> class TypesT>
struct Dynamic
{
using Types = TypesT<Dynamic>;
using Null = typename Types::Null;
using Number = typename Types::Number;
using Vector = typename Types::Vector;
Dynamic()
{
construct<Null>( nullptr );
}
~Dynamic()
{
m_erasureFuncs.pDestroy( &m_data );
}
Dynamic( const Dynamic &d ) :
m_typeValue( d.m_typeValue ),
m_erasureFuncs( d.m_erasureFuncs )
{
m_erasureFuncs.pCopy( &m_data, &d.m_data );
}
Dynamic( Dynamic &&d ) = delete;
template <class T, class = disable_if_same_or_derived<Dynamic, T>>
Dynamic( T &&value )
{
construct<unqual<T>>( std::forward<T>( value ) );
}
Dynamic &operator=( const Dynamic &d ) = delete;
Dynamic &operator=( Dynamic &&d ) = delete;
private:
static TypeValue to_type_value( TypeArg<Null> )
{
return TypeValue::Null;
}
static TypeValue to_type_value( TypeArg<Number> )
{
return TypeValue::Number;
}
static TypeValue to_type_value( TypeArg<Vector> )
{
return TypeValue::Vector;
}
template <class T, class...Args>
void construct( Args&&...args )
{
m_typeValue = to_type_value( TypeArg<T>() );
m_erasureFuncs = TypeArg<T>();
new ( &m_data ) T( std::forward<Args>( args )... );
}
private:
TypeValue m_typeValue;
ErasureFuncs m_erasureFuncs;
std::aligned_union_t<0, Null, Number, Vector> m_data;
};
}
void test1();
void test2();
动态测试_1.cpp:
#include "dynamic_test.h"
#include <vector>
namespace
{
template <class DynamicType>
struct Types
{
using Null = std::nullptr_t;
using Number = long double;
using Vector = std::vector<DynamicType>;
};
using D = dynamic::Dynamic<Types>;
}
void test1()
{
D::Vector v1;
v1.emplace_back( D::Number( 0 ) );
}
动态测试_2.cpp:
#include "dynamic_test.h"
#include <vector>
namespace
{
template <class DynamicType>
struct Types
{
using Null = std::nullptr_t;
using Number = double;
using Vector = std::vector<DynamicType>;
};
using D = dynamic::Dynamic<Types>;
}
void test2()
{
D::Vector v1;
v1.emplace_back( D::Number( 0 ) );
}
主要.cpp:
#include "dynamic_test.h"
int main( int, char* const [] )
{
test1();
test2();
return 0;
}
运行这段代码会产生一个 SIGSEGV,堆栈跟踪如下:
1 ?? 0x1fa51
2 dynamic::Dynamic<(anonymous namespace)::Types>::~Dynamic dynamic_test.h 66 0x40152b
3 std::_Destroy<dynamic::Dynamic<(anonymous namespace)::Types>> stl_construct.h 93 0x4013c1
4 std::_Destroy_aux<false>::__destroy<dynamic::Dynamic<(anonymous namespace)::Types> *> stl_construct.h 103 0x40126b
5 std::_Destroy<dynamic::Dynamic<(anonymous namespace)::Types> *> stl_construct.h 126 0x400fa8
6 std::_Destroy<dynamic::Dynamic<(anonymous namespace)::Types> *, dynamic::Dynamic<(anonymous namespace)::Types>> stl_construct.h 151 0x400cd1
7 std::vector<dynamic::Dynamic<(anonymous namespace)::Types>>::~vector stl_vector.h 426 0x400b75
8 test2 dynamic_test_2.cpp 20 0x401796
9 main main.cpp 6 0x400a9f
奇怪的是,构造 Vector 会将我们直接带到析构函数。
非常奇怪的是,当我们执行以下操作时,这些错误消失了:
这是一个确实有效的实现示例:
template <class Types>
struct Dynamic
{
using Null = typename Types::Null;
using Number = typename Types::Number;
using Vector = typename Types::template Vector<Dynamic>;
...
struct Types
{
using Null = std::nullptr_t;
using Number = long double;
template <class DynamicType>
using Vector = std::vector<DynamicType>;
};
当我们使用链接时间优化 (LTO) 进行编译时,我们还会看到一些与 ODR 违规相关的警告:
dynamic_test.h:51: warning: type ‘struct Dynamic’ violates the C++ One Definition Rule [-Wodr]
struct Dynamic
^
是否有人对导致此问题的原因有所了解?
最佳答案
好吧,我花了一段时间来断断续续地玩这个,但我终于得到了一个非常简单的拷贝,它是问题的核心。首先,考虑 test1.cpp
:
#include "header.h"
#include <iostream>
namespace {
template <class T>
struct Foo {
static int foo() { return 1; };
};
using D = Bar<Foo>;
}
void test1() {
std::cerr << "Test1: " << D::foo() << "\n";
}
现在,test2.cpp
与此完全相同,除了 Foo::foo
返回2,底部声明的函数调用test2
并打印 Test2:
等等。接下来,header.h
:
template <template <class> class TT>
struct Bar {
using type = TT<Bar>;
static int foo() { return type::foo(); }
};
void test1();
void test2();
最后,main.x.cpp
:
#include "header.h"
int main() {
test1();
test2();
return 0;
}
您可能会惊讶地发现这个程序打印:
Test1: 1
Test2: 1
当然,那只是因为我用:
g++ -std=c++14 main.x.cpp test1.cpp test2.cpp
如果我颠倒最后两个文件的顺序,它们都会打印 2。
发生的事情是链接器最终使用它遇到的第一个定义 Foo
到处都需要它。嗯,但我们定义了 Foo
在一个匿名命名空间中,这应该给它内部链接,避免这个问题。所以我们只编译一个 TU 然后使用 nm
在上面:
g++ -std=c++14 -c test1.cpp
nm -C test1.o
这会产生以下结果:
U __cxa_atexit
U __dso_handle
0000000000000087 t _GLOBAL__sub_I__Z5test1v
0000000000000049 t __static_initialization_and_destruction_0(int, int)
0000000000000000 T test1()
000000000000003e t (anonymous namespace)::Foo<Bar<(anonymous namespace)::Foo> >::foo()
0000000000000000 W Bar<(anonymous namespace)::Foo>::foo()
U std::ostream::operator<<(int)
U std::ios_base::Init::Init()
U std::ios_base::Init::~Init()
U std::cerr
0000000000000000 r std::piecewise_construct
0000000000000000 b std::__ioinit
U std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
除了大写字母与小写字母之外,现在不要担心字母。小写符号是私有(private)的,就像我们期望的内部链接符号一样。大写符号是公共(public)的,具有外部链接并暴露给链接器。
有趣但并不奇怪的是,虽然 Foo
可能有内部链接,Bar
才不是!第一个翻译单元已经定义了符号 Bar<Foo>
与外部链接。第二个翻译单元做同样的事情。因此,当链接器链接它们时,它会看到两个翻译单元试图通过外部链接定义相同的符号。请注意,它是一个内联定义的类成员,因此它是隐式内联的。所以链接器一如既往地处理这个问题:它只是默默地删除它在第一个定义之后遇到的所有定义(因为符号已经定义;这就是链接器的工作方式,从左到右)。所以Foo
在每个 TU 中都正确定义,但是 Bar<Foo>
不是。
最重要的是,这是 ODR 违规行为。您需要重新考虑一些事情。
编辑:这似乎实际上是 gcc 中的一个错误。该标准的措辞暗示 Foo
s 在这种情况下应该被独特对待,因此 Bar
在每个 Foo
上模板化应该是分开的。错误链接:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70413 .
关于c++ - GCC 6.3.0 中的 ODR 违规,类型定义在两个单独的翻译单元中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43239762/
我试图要求 test/unit 的新版本(即不是与 ruby 捆绑的版本) .根据 instructions我用 gem i test-unit 安装它.但是现在当我需要 test/unit我似乎
简短版本是: 我有一个 systemd 单元,我想在调用时检查脚本的返回代码: systemctl status service.service 长版本:我有一个 lsb init 脚本正是这样做的,
我正在使用反射动态创建一个类的实例,这工作正常,除非尝试通过单元测试执行此操作 - 我使用的是 MS 测试框架。 我收到熟悉的错误:“无法加载文件或程序集‘Assy’或其依赖项之一。系统找不到指定的文
我想知道测试网站“界面功能”的最佳实践是什么。 我对哪些方法可用于测试界面和动态生成的内容感兴趣。特别是,我很难弄清楚是否可以为需要用户交互的操作创建自动化测试,或者这是否只是浪费时间,我应该让一些
我有一个简单的 Python 服务,其中有一个无限执行某些操作的循环。在各种信号上,sys.exit(0) 被调用,这导致 SystemExit 被引发,然后如果可以的话应该进行一些清理。 在测试中,
我正在使用 OpenCV 2.4.2 这是 OpenCV 文档中的引文 C++: void HoughLinesP(InputArray image, OutputArray lines, doubl
忙于 C# 中的自动化测试用例,我们需要在每次测试后恢复数据库快照。问题是,当运行多个测试时它会失败,因为“其他用户正在使用数据库时无法更改数据库状态。” 我们使用 SqlConnection.Cle
我阅读了 C# 规范并用谷歌搜索了它,但一无所获。 我 99% 肯定 C# 中没有像单元命名空间指令这样的功能,但问题是:为什么?是否有惯用或技术原因? 这很方便,尤其是当我们的大部分文件都由单个命名
我目前正在尝试向我的应用程序(一个非常老的项目......评论说 iOS 2.0)添加单元测试(精确的应用程序测试)并且总是偶然发现 undefined symbols for architectur
我正在使用Delphi 7,并且有一个新单元要在我的项目中使用。我已经编译了新的。当我尝试通过将其添加到uses子句在项目中使用此单元时,出现错误,提示未找到.dcu文件。我还尝试将文件的完整路径放在
场景:我需要编写一个复杂的nHibernate查询,该查询将返回预计的DTO,但是我想使用TDD方法。该方法如下所示: public PrintDTO GetUsersForPrinting(int
您可以通过运行以下命令在事件 html 设置中显示 Jupyter 笔记本: $ jupyter nbconvert untitled.ipynb --to slides --post serve 有
如何在一个网站上拥有多个 AdSense 单元? Google 提供的唯一代码是按单位计算的。 (adsbygoogle = window.adsbygoogle || []).push({})
我刚刚开始为大量代码编写测试。有很多类依赖于文件系统,即读取 CSV 文件、读/写配置文件等。 当前测试文件存储在项目(这是一个 Maven2 项目)的 test 目录中,但由于多种原因该目录并不总是
我对 TDD 还很陌生,在单元测试方面也不是很老练,所以才有这个问题。我有这个用 PHP 编写的遗留函数 function foo(){ x = bar(); y = baz();
我创建了一个程序,在 Swing 窗口的一侧显示结果过滤选项,但默认情况下它们水平相邻显示,这浪费了我在 BorderLayout 的西侧分配的空间。我可以在构造函数或添加语句中传递任何内容来将它们堆
标题不好的借口:如果有人能更好地描述它,请做。 我有一个 WeakList类,它“基本上”是一个 List> (虽然不是字面意义上的派生自列表,但它应该对用户完全透明)。 现在的基本思想是“如果引用的
我正在尝试在 UITableView 上添加两个原型(prototype)单元。但是,我不知道如何验证是否能够为每个原型(prototype)“返回”正确的单元格。你们能帮我一下吗? func ta
我正在使用 CloudKit 作为数据库创建一个简单的待办事项列表应用程序。目前我可以添加和删除对象,但对编辑对象感到困惑。 编辑项目 Controller protocol EditItemCont
我正在针对以下任务训练 RNN:给定一个包含 30 个单词的序列,然后将该序列分类为二进制类。 在我的网络中拥有超过 30 个单元(LSTM、GRU 或普通 RNN)有好处吗?我在网上看到过很多例子,
我是一名优秀的程序员,十分优秀!