我在一个库中有一个类,如果这个类有一个模板方法,它有一个静态变量,使用库中的方法将访问一个不同的静态变量,而不是使用库外的方法。这种行为发生在windows中,在linux中它按预期工作。我准备了一个示例,有两个场景,在这两种情况下,类都在库中定义,(LibA),并且测试程序链接到它(temptest)。在本解释中代码被简化了,完整的代码可以在github库https://github.com/pyaggi/temptest中找到。示例代码使用cmake,因此在任何平台上编译都很容易。
1-使用类模板的方案
//liba.h (library)
template<typename T>
class TestClass_template
{
public:
TestClass_template()
{
}
template<typename T1>
static T1 incCounter()
{
static T1 counter=0;
return counter++;
}
private:
T val;
};
class LIBA_PUBLIC TestClass_long:public TestClass_template<long>
{
public:
TestClass_long();
static short test_incCounter_short();
};
//liba.cpp (library)
TestClass_long::TestClass_long()
{
}
short TestClass_long::test_incCounter_short()
{
return incCounter<short>();
}
//main.cpp (temptest, program)
std::cout<<"Output from class template example"<<std::endl;
for (int c=0;c<2;c++)
{
std::cout<<"TestClass<long>::incCounter_short "<<TestClass_template<long>::incCounter<short>()<<std::endl;
TestClass_long::test_incCounter_short();
std::cout<<"TestClass_long::incCounter_short "<<TestClass_long::incCounter<short>()<<std::endl;
TestClass_long::test_incCounter_short();
}
Linux中的输出
Output from templated class example
TestClass<long>::incCounter_short 0
TestClass_long::incCounter_short 2
TestClass<long>::incCounter_short 4
TestClass_long::incCounter_short 6
Windows中的输出
Output from templated class example
TestClass<long>::incCounter_short 0
TestClass_long::incCounter_short 1
TestClass<long>::incCounter_short 2
TestClass_long::incCounter_short 3
在Windows中调用TestClass_long::test_incCounter_short();
访问不同的静态变量,生成顺序输出(0,1,2,3);在Linux中,它访问相同的静态变量,从而生成交错输出(0,2,4,6)。
2-使用常规类的方案
//liba.h (library)
class LIBA_PUBLIC TestClass
{
public:
TestClass()
{
}
template<typename T1>
static T1 incCounter()
{
static T1 counter=0;
return counter++;
}
static short test_incCounter_short();
private:
long val;
};
//liba.cpp (library)
short TestClass::test_incCounter_short()
{
return incCounter<short>();
}
//main.cpp (temptest, program)
std::cout<<"Output from regular class example"<<std::endl;
for (int c=0;c<2;c++)
{
std::cout<<"TestClass::incCounter_short "<<TestClass::incCounter<short>()<<std::endl;
TestClass::test_incCounter_short();
std::cout<<"TestClass::incCounter_short "<<TestClass::incCounter<short>()<<std::endl;
TestClass::test_incCounter_short();
}
Linux中的输出
Output from templated class example
TestClass::incCounter_short 0
TestClass::incCounter_short 2
TestClass::incCounter_short 4
TestClass::incCounter_short 6
Windows中的输出
Output from templated class example
TestClass::incCounter_short 0
TestClass::incCounter_short 1
TestClass::incCounter_short 2
TestClass::incCounter_short 3
使用g和clang执行Linux测试。
使用msvc(cl.exe)和clang(msvc-cl.exe)执行Windows测试。
所以我有两个问题:
1-C17的预期行为是什么?
2-有没有可能让MSVC像linux一样运行?
1条答案
按热度按时间7vux5j2d1#
在做了一些研究之后,阅读了这篇优秀的文章from Michele Caini,一个伟大的泛型程序员;我可以回答两个问题:
1-C++17的预期行为是什么?
当前的标准修订版都没有解决库的处理问题,跨边界代码没有标准化,因此这取决于编译器设计者。
2-有没有可能让MSVC像linux一样运行呢?简单地说,答案是否定的。但是有时候有一种方法可以解决这个问题。
微软的Xiang Fan(查看bug报告)提出了一个解决方案,使用宏声明只在一个单元中定义模板化的静态变量。这种解决方案在大多数情况下不起作用,因为你破坏了泛型编程的整个目的,即你不知道你将在哪里使用什么类型。
我发现了一个解决方案,如果你创建的静态变量不依赖于模板的类型,那么这个解决方案对我来说是有效的。你必须使用一个方法或者一个全局函数来为你检索静态变量。答案中没有说明这种情况,但是有时候你可以按照这个方向重新设计问题。为了简单起见,我将给予你一个没有类的例子: