c++ 20模板编译通过

  • 本文关键字:编译 c++ c++ templates
  • 更新时间 :
  • 英文 :


我对c++模板编译方式的变化有一个问题,在c++ 17和c++ 19标准之间。用于在VS2017中编译的代码在升级到VS2019或VS2022后抛出编译器错误。

情况与编译器现在在看到这个定义("first pass")时对模板定义运行基本语法检查有关,而不仅仅是在模板实际使用时。

代码例1:

class Finder
{
template<typename T>
T convert_to(HANDLE h)
{
return Converters::Converter<T>::Convert(get_data(h));
}
};

在这里,模板class Converter<>驻留在命名空间Converters中,get_dataFinder的成员函数,它返回一些可以传递给Convert函数的东西。

因为我们处理的是模板,所以这段代码位于头文件& Finder.h&quot中。头文件没有#include "Converters.h"。Finder.h在几个项目之间共享,其中一些项目甚至不知道Converters.h文件命名空间。

只要没有代码调用MyClass::convert_to<>函数,这将在VS2017中编译,但在VS2019和VS2022中不会编译:

error C3861: 'Converters': identifier not found

显而易见的解决方案当然是#include "Converters.h"在这个头文件中,或者在预编译的头文件中。然而,如前所述,并不是所有使用MyClass的地方都知道Converters.h。另一种解决方案是在Converters.h头文件中使用古老的#define CONVERTERS_H,并将函数定义包含在#ifdef CONVERTERS_H中,但这看起来真的很难看。

我的问题是:是否有一种方法可以防止编译器这样做"第一次通过"?还是重新编写这段代码以使其能够编译?我不介意这是否是MS特有的;没有其他编译器会看到这些代码。

代码示例2:

class MyClass2
{
template<class T>
static void DoSomething(T* ptr) { static_assert(false, "Don't do this"); }
// lots more member functions, most of them 'static'
};
template<> void MyClass::DoSomething(CWnd* ptr) { /*some useful code*/ }
/// and some more specializations of DoSomething

的目的是,static_assert应该发出一个错误消息,每当DoSomething被调用时,没有为该模板函数定义显式特化的参数。这在VS2017中有效,但在VS2022中,"第一次通过"编译器触发static_assert.

我想知道,除了用运行时断言替换static_assert之外,如何才能达到这种效果。

还是我想错了方向?

感谢汉斯

第一种情况需要某种形式的前向声明,这是不可避免的。

第二种情况,只需要做一点小小的改变就可以处理。

#include <type_traits>
class CWnd {};
class MyClass2
{
public:
template<class T, class Y=T>
static void DoSomething(T* ptr) { static_assert(!std::is_same_v<Y,T>, "Don't do this"); }
};
template<> void MyClass2::DoSomething(CWnd* ptr) { /*some useful code*/ }
void foo()
{
int a;
CWnd b;
MyClass2::DoSomething(&a); // ERROR
MyClass2::DoSomething(&b); // OK
}

(部分答案)

要修复MyClass2,通常的技巧是使false依赖于T,这样第一次传递就不会触发断言。

// dependent false
template <typename>
constexpr bool dep_false() { return false; }
class MyClass2
{
template<class T>
static void DoSomething(T* ptr) {
static_assert(dep_false<T>(), "Don't do this");
}
// lots more member functions, most of them 'static'
};
// specialization example
template<>
void MyClass2::DoSomething<int>(int* ptr) {
std::cout << "int* is OKn";
}

最新更新