模板不完整模板的别名类型

Aliasing type of incomplete template of template

提问人:LarrxX 提问时间:9/22/2023 最后编辑:LarrxX 更新时间:9/23/2023 访问量:61

问:

几天来我一直在为此苦苦挣扎。我正在将一些代码移植到 MacOS/AppleClang,我们有非常繁重的模板化代码,这些代码在 MSVC 上正确构建,但在 clang 上失败(可以理解,因为在阅读之后,我们的代码不符合标准)。但我真的找不到一种方法来正确地做到这一点。

下面是原始代码,可在 MSVC 上构建并正常工作:

template<typename ValueType>
class MemoryDataLayout
{
  //Do stuff;
};

template<typename LayoutType = MemoryDataLayout>
class MemoryBufferView
{
public:
  using this_container = MemoryBufferView<LayoutType>;
  using layout_type = LayoutType;
  //Do stuff;
};

不编译,因为 Clang 找不到类型。MemoryDataLayout

但是,如果我这样写:

template<template <typename Type> class LayoutType = MemoryDataLayout>
class MemoryBufferView
{
public:
  using this_container = MemoryBufferView<LayoutType>;
  using layout_type = LayoutType;
  //Do stuff;
};

可以理解的是,编译器抱怨using layout_type = LayoutType;

理想情况下,我知道我应该写作,但从这个上下文中似乎看不到类型。using layout_type = LayoutType<Type>;

我知道我可以这样写出来:

template<typename Type, template <typename> class LayoutType = MemoryDataLayout>
class MemoryBufferView
{
public:
  using this_container = MemoryBufferView<LayoutType>;
  using layout_type = LayoutType<Type>;
  //Do stuff;
};

但这意味着在整个代码库中更改大量代码,因此,如果我能使其与一个模板参数保持“兼容”,那将是理想的......如果可能的话。

哦,不幸的是,我们仅限于 C++17,没有什么更新的。

我现在没有想法,所以任何帮助将不胜感激。

[编辑了解更多详情]

在代码库中使用默认布局实例化此类的方式是MemoryBufferView<char> m;

我发现唯一可以保持大多数代码库兼容的紧密解决方案如下:

template<typename ValueType>
class MemoryDataLayout
{
//Do stuff;
};

template<typename T, template<typename> class LayoutType = MemoryDataLayout>
class MemoryBufferView
{
public:
  using this_container = MemoryBufferView<T, LayoutType>;
  using layout_type = LayoutType<T>;
//Do stuff;
};

void f(){
    MemoryBufferView<char> m;
}

但这仅在使用默认布局调用 MemoryBufferView 时有效(否则我必须更改调用)。

我可以忍受这一点,但出于好奇,如果有更好的东西,我很乐意阅读:)

[最终编辑]

我最终使用了我上面提出的解决方案,它更干净,更准确地满足我们想要的情况。

C++ 模板 C++17 叮当

评论

0赞 Oersted 9/22/2023
MemoryDataLayout 是一个模板,而不是一个类型。时期。User:11638718 Answers应该可以完成这项工作(尽管它缺乏解释),如果你不想改变你的设计(这可能是可以理解的)。
0赞 Caleth 9/22/2023
这注定了什么?哪些操作可以做和共享?MemoryBufferView<char>charMemoryDataLayout<T>
0赞 Caleth 9/22/2023
您是否曾经使用默认模板参数实例化此模板?MSVC 拒绝了这一点
0赞 LarrxX 9/22/2023
MemoryBufferView<char>应该是 MemoryBufferView<MemoryDataLayout<char>>' 我想强调的是,这种恐怖不是我的代码,我只是想让它达到规范:)
0赞 Caleth 9/22/2023
“if I can keep it 'compatible' with the one template argument”(如果我能保持它与一个模板参数的“兼容”)一个模板参数兼容。原始模板与零参数不兼容template<typename Type, template <typename> class LayoutType = MemoryDataLayout> class MemoryBufferView

答:

1赞 康桓瑋 9/22/2023 #1

您可以制作别名模板layout_type

template<template <typename Type> class LayoutType = MemoryDataLayout>
class MemoryBufferView
{
public:
  using this_container = MemoryBufferView<LayoutType>;
  template<typename ValueType>
  using layout_type = LayoutType<ValueType>;
  //Do stuff;
};

评论

0赞 LarrxX 9/22/2023
在这种情况下,您将如何传递类型?它应该与 相同。我很快尝试了一下,但它甚至没有编译,很抱歉说':-) 我编辑了我的问题,以获取有关预期结果的更多详细信息。ValueTypeType
0赞 Caleth 9/22/2023
@LarrxX类型和类型都不是,但它们都是未绑定的模板参数。有点不幸的是,你甚至可以给出一个名字。TypeValueTypeType
0赞 LarrxX 9/22/2023
但是,您将如何在示例中实例化?ValueType
0赞 康桓瑋 9/22/2023
@LarrxX 如果我理解正确,似乎您只需要将默认模板参数更改为 即 godbolt.org/z/1hq93nfbeMemoryBufferViewMemoryDataLayout<char>
0赞 LarrxX 9/22/2023
或者实际上只是删除默认模板值。因为使用零参数是行不通的,而且绝对不应该行。但是,我更喜欢使用我自己发布的解决方案,因为它更接近开发人员的初衷。感谢您的帮助!
3赞 Caleth 9/22/2023 #2

当前代码从未使用该模板参数的默认值。MSVC 有点不合规,因为它将模板的一些检查推迟到实例化时间。 不使用默认的模板参数,则完全替换为 。如果您认为会影响 .MemoryBufferView<char>charMemoryDataLayoutMemoryBufferView<char>

您可以进行的影响最小的更改是删除不正确的默认参数:

template<typename LayoutType>
class MemoryBufferView
{
public:
  using this_container = MemoryBufferView<LayoutType>;
  using layout_type = LayoutType;
  //Do stuff;
};

Clang 会接受它,并且您不会更改现有代码的行为。

评论

0赞 Swift - Friday Pie 9/22/2023
MSVC v.15.x 也充满了回归和偏转完全有效的代码。还应该注意“一致性”标志,这是默认设置的。事实上,它与一致性相反,因为编译器开始以不符合 ISO 的方式运行。/permissive-
0赞 LarrxX 9/22/2023 #3
template<typename ValueType>
class MemoryDataLayout
{
//Do stuff;
};

template<typename T, template<typename> class LayoutType = MemoryDataLayout>
class MemoryBufferView
{
public:
  using this_container = MemoryBufferView<T, LayoutType>;
  using layout_type = LayoutType<T>;
//Do stuff;
};

void f(){
    MemoryBufferView<char> m;
}

我最终使用了这种方法,这种方法更正确,实际上符合原始开发人员的意图。感谢大家的帮助和投入。