我是开源库的开发人员.我们的一个类是模仿一堆不同的类型.目前,该定义位于头文件中,这会对编译时间产生负面影响,并且还会强制用户包含多于所需的标头.我的目标是:
为了减少编译时间,我想使用C++ 11引入的显式实例化声明.
类方法和成员的定义都是静态的,必须与实现文件中的声明分开.它们应该可以在库外部和内部使用,而无需用户进行显式实例化定义或类似的任何操作.
这必须在支持C++ 11的所有常见编译器上运行跨平台(Visual Studio 2013 +,GCC等)
C++ 11为类模板提供了新功能,特别是" 显式实例化声明 ".据我所知,这可以在这种情况下使用.以前的问题在类似的上下文中处理了这个问题,例如如何使用extern模板和分离模板类的定义/实例化而没有'extern'但是那些不处理库导出,如果客户端尝试使用共享库,它们的解决方案会导致链接器错误.
目前我已经设法以在Visual Studio 2015上编译,链接和运行的方式实现它,但我不确定我是否正确使用了关键字,尤其是在这种情况下的__declspec.这就是我得到的(简化):
// class.h
template<typename T>
class PropertyHelper;
template<typename T>
class PropertyHelper<const T>
{
public:
typedef typename PropertyHelper<T>::return_type return_type;
static inline return_type fromString(const String& str)
{
return PropertyHelper<T>::fromString(str);
}
static const int SomeValue;
};
template<>
class EXPORTDEF PropertyHelper<float>
{
public:
typedef float return_type;
static return_type fromString(const String& str);
static const int SomeValue;
};
extern template EXPORTDEF class PropertyHelper<float>;
Run Code Online (Sandbox Code Playgroud)
最后一行是显式实例化声明.据我所知,这意味着客户不必每次都自己申报.EXPORTDEF是Windows上的__declspec(dllexport)或__declspec(dllimport)的定义.我不确定是否需要将其放在上面的行中,因为以下内容还编译,链接和运行:
extern …Run Code Online (Sandbox Code Playgroud) 在C++ 11中,我们提供了固定宽度的整数类型,例如std::int32_t和std::int64_t,它们是可选的,因此不是编写跨平台代码的最佳选择.然而,我们也得到了各类非可选变型:例如"快"的变体,如std::int_fast32_t和std::int_fast64_t,以及"最小尺寸"变体,例如std::int_least32_t,它都至少指定数目的大小位.
我正在处理的代码是基于C++ 11的跨平台库的一部分,它支持在最流行的Unix/Windows/Mac编译器上进行编译.现在出现的一个问题是,如果用C++ 11固定宽度整数类型替换代码中的现有整数类型是否有优势.
使用类似变量的缺点std::int16_t和std::int32_t是缺乏保证它们是可用的,因为只提供他们如果实现直接支持的类型(根据http://en.cppreference.com/w/cpp/types/integer).
但是,因为int至少16位且16位对于代码中使用的整数足够大,所以使用std::int_fast16_tover int呢?它提供了一个好处,以取代所有int类型的std::int_fast16_t,所有unsigned int通过的std::uint_fast16_t那样,或者这是不必要的?
Anologously,如果知道所有支持的平台和编译器配备了int至少32位的大小,是否有意义通过替换他们std::int_fast32_t和std::uint_fast32_t分别?
我是一个库的开发人员,我们的旧代码使用sscanf()和sprintf()从/到字符串读/写各种内部类型.我们遇到过使用我们库的用户的问题,并且其语言环境与我们基于XML文件的语言环境不同("C"语言环境).在我们的例子中,这导致从这些XML文件解析的值不正确,以及在运行时以字符串形式提交的值.区域设置可以由用户直接更改,但也可以在用户不知情的情况下进行更改.如果区域设置更改发生在另一个库中,例如GTK,这是一个错误报告中的"犯罪者",就会发生这种情况.因此,我们显然希望从语言环境中删除任何依赖关系,以永久地摆脱这些问题.
我已经在float/double/int /的上下文中阅读了其他问题和答案,特别是如果它们被一个字符分隔或位于括号内,但到目前为止,我发现的建议解决方案并不令我们满意.我们的要求是:
除了标准库之外,不依赖于库.因此,使用boost中的任何内容都不是一种选择.
必须是线程安全的.这具体涉及可以全局更改的区域设置.这对我们来说真的很糟糕,因为我们库的一个线程可能会受到用户程序中另一个线程的影响,该线程也可能正在运行一个完全不同的库的代码.setlocale()因此,任何直接受影响的东西都不是一种选择.此外,由于线程中的竞争条件,在开始读/写之前设置区域设置并将其设置回原始值不是解决方案.
虽然效率不是最重要的优先级(#1和#2),但它仍然是我们关注的问题,因为字符串可能会在运行时频繁地读取和写入,具体取决于用户的程序.越快越好.
编辑:作为补充说明:boost::lexical_cast不保证不受语言环境的影响(来源:boost :: lexical_cast <>的语言环境不变保证).即使没有要求#1,这也不是解决方案.
到目前为止,我收集了以下信息:
std::to_string,std::stod,std::stof,等取决于全球区域只是sscanf的方式和sprintf做的,这是非常不幸的,我不理解的,考虑到的std ::螺纹已被添加.std::stringstream似乎是一般的解决方案,因为它在语言环境的上下文中是线程安全的,但一般来说如果保护正确的话.但是,如果它每次都是新建的,那么它很慢(良好的比较:http://www.boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast/performance.html).我假设这可以通过配置和使用每个线程一个这样的流来解决,每次使用后清除它.但是,问题在于它不能像以下那样容易地解决格式sscanf(),例如:" { %g , %g } ".sscanf() 例如,我们需要能够阅读的模式是:
" { %g , %g }"" { { %g , %g } , { %g , %g } }"" { top: { %g , %g } …在我们的跨平台开源库中,我们从std :: exception派生,以便定义可以在库代码和用户代码中捕获的自定义异常.我看到这实际上是一个推荐的过程,但在Visual Studio 2015中(或者更确切地说,随附的新MSVC版本?)在实现类中抛出警告(警告C4275) - 另请参见此处:如何从一个派生类的dllexport的std :: runtime_error?
当然我们可以忽略错误,但这对我来说似乎不对.
与较旧的Visual Studio版本相比,出现警告的原因似乎是std :: exception曾经在较旧的MSVC版本中导出,但同时不再导出.在任何一种情况下,我觉得从未以"正确的方式"继续以将其编译到库中的形式.
从我在答案中读到的,更好的方法是"内联"类,因为导出基类(std :: exception)可能会导致更多的复杂化.如果我理解正确,这里的"内联"意味着不使用"内联"关键字,而是将定义移到标题中而不导出它.这是否正确?
假设这就是我的意思:我的问题是,如果编译的库抛出异常(在其中一个标题中定义)将允许在动态链接此库的可执行文件中正确捕获异常.但是如果编译器不同呢?运行时类型信息(RTTI)在这里似乎是相关的,所以即使使用不同的编译器版本甚至不同的编译器,这也保证以这种方式工作?如果这不起作用,如何以"正确"的方式解决这个问题?
我想在我们的开源库中使用C++ 11关键字thread_local,它可以在静态变量的上下文中在许多平台(Windows,Linux,Mac OS,...)上动态或静态链接.这个变量是一个类类型,它基本上只是封装了一个std :: stringstream变量并初始化它以适应我们的字符串流格式要求.出于性能原因,我们希望将此静态提供(有关更多详细信息,请参阅我之前的问题),如果每个线程完成此操作,则可以.
全局变量应该用在静态模板化类方法中,这些方法必须在头文件中实现.但是,如果我理解正确的话,这意味着库的用户可以在他们的可执行代码中包含这个头,这会将模板化的方法编译成可执行文件.然后,这些方法将从可执行文件的线程中访问提到的全局变量.我如何声明/定义静态变量才能工作,即我需要导出变量或类类型还是足以将其声明为"static thread_local X"?这是我目前的声明:
// SharedStringstream.h
#include <sstream>
// Export stands for _declspec(dllimport) or (dllexport) respectively
class EXPORT SharedStringstream
{
public:
SharedStringstream();
static thread_local SharedStringstream s_sharedStreamInstance;
std::stringstream d_sharedStream;
};
Run Code Online (Sandbox Code Playgroud)
和定义:
// SharedStringstream.cpp
#include "SharedStringStream.h"
SharedStringstream SharedStringstream::s_sharedStreamInstance();
SharedStringstream::SharedStringstream()
{
d_sharedStream.imbue(std::locale("C"));
d_sharedStream << std::skipws;
d_sharedStream >> std::skipws;
}
Run Code Online (Sandbox Code Playgroud)
没有导出我得到链接器错误,我在Visual Studio 2015中收到以下错误:
错误C2492'public:static SharedStringstream SharedStringstream :: s_sharedStreamInstance':具有线程存储持续时间的数据可能没有dll接口
这里给出了更多信息,其中基本上表明thread_local可能不会导出变量.为此,我必须将它从类中移出到我的命名空间中,这是唯一的方法吗?
此外:"线程本地存储"上的MSDN页面说明以下关于thread_local和DLL:
thread属性的使用可能会干扰DLL导入的延迟加载.
我们在内部使用DLL的延迟加载来处理我们的库所包含的一些插件,但是不会对该变量进行任何调用.我假设用户可以延迟加载库,尽管我们没有正式支持这个.假设我们不支持延迟加载我们的库并且不在内部调用任何延迟加载的dll中的变量,我们是否能够确定这在任何上下文中都不会成为问题?
我的问题中没有考虑过任何问题吗?
我正在使用TortoiseHG版本2.5.1
我是一个开源项目的一部分,我们使用不同的分支(主要是当前的ABI,API和默认分支),这些分支通常需要合并.在这些情况下,我使用TortoiseHG工作台中的"与本地合并"上下文菜单选项.例如,将"v0-8"分支合并到"default"分支时,使用TortoiseHG的默认设置生成以下提交消息:
与v0-8合并
我宁愿得到一个自动生成的消息,如(或类似)这个:
将v0-8合并为默认值
而默认情况下代表任何当前选择的本地分支,v0-8代表,我们要合并到当地的分公司之一.这条消息可以清楚地理解发生了什么,而不必每次都手动输入.
我怎样才能做到这一点?
我想在UTF-32代码点上使用正则表达式,并发现此引用声明std :: regex_traits必须由用户定义,以便可以使用std :: basic_regex.未来似乎没有计划改变.
为什么会这样呢?
这是否与Unicode说组合代码点必须被视为等于单代码点表示(如变形'ä'表示为单个代码点或a和圆点为两个独立的代码点)这一事实有什么关系?
鉴于只支持单码点字符的简化,这种特性是否可以很容易地定义,或者这可能是非平凡的还是需要进一步的限制?
我想在cpp文件的匿名命名空间中有一个模板函数,纯粹是作为不同大小的std :: array类型的帮助函数。在此翻译单元之外的任何地方都不能使用此功能。
令我惊讶的是,当我在MSVC 14.1(简化代码)中尝试此操作时,此问题立即解决了:
namespace
{
template<std::size_t SIZE>
bool isPushed(std::uint32_t id, std::array<std::uint32_t, SIZE>& states)
{
if(id >= states.size())
{
return false;
}
return ((states[id] & 32U) > 0U);
}
}
Run Code Online (Sandbox Code Playgroud)
这符合C ++标准吗?
据我所知,模板总是需要在标头中声明(并且通常也要实现),在这种情况下为什么不这样做呢?