gpt4 book ai didi

c++ - C++方法从另一个模板类和 namespace 泄漏

转载 作者:行者123 更新时间:2023-12-02 09:59:53 25 4
gpt4 key购买 nike

抱歉,很长的帖子。我在将其分解为基本方面或查找正确的措词时遇到一些麻烦,因此也对它进行了谷歌搜索-如果您以前曾问过这个问题,请原谅我。 ;)我只会在这里描述我所面临的整体情况,并尝试使其尽可能完整。
语境
我目前正在跟踪一个非常奇怪的错误,其中在我自己的类导致非常奇怪的编译时错误之前包括一些库X的 header 。这里的细节不是那么重要(我将在稍后给出一个最小的示例!),但是对于上下文:我正在使用名为cereal的库序列化对象,并且突然告诉我我的类不是默认可构造的不再。
在将包含在内的破坏邪恶的 header 切成碎片之后,我终于找到了发生的情况,并在一个简化的示例中重新创建了该错误,但是我不知道为什么会像它们那样起作用(或不起作用),也许有人可以向我解释。 :)
初赛X包含的 header 的某些部分破坏了cereal中的类型特征,该特征决定了给定的类T是否可以由cereal::access默认构造。
因此,我们首先需要的是类型特征。这是一种类似于 Cereal 特性工作原理的实现方式(但不尽相同,为简单起见,将其精简地概括如下):

#include <type_traits>

namespace cereal {

using yes = std::true_type;
using no = std::false_type;

struct access {
template <class T>
struct construct {
T foo;
};
};

//! Determines whether the class T can be default constructed by cereal::access
template <class T>
struct is_default_constructible
{
template <class TT>
static auto test(int) -> decltype(cereal::access::construct<TT>(), yes());

template <class>
static no test(...);

static const bool value = std::is_same<decltype(test<T>(0)), yes>::value;
};
}
基本思想是:如果可以默认构造 cereal::access:construct<T>(因此也可以默认构造 T),则适用 test(int)作为返回类型的 yes = std::true_type方法,该方法用于确定 static const bool value,否则使用省略号版本,该方法返回 no = std::false_type
我首先通过将以下代码附加到同一文件中进行了测试:
class HasDefault {
public:
HasDefault() = default;
};


class HasNoDefault {
public:
HasNoDefault() = delete;
};

class HasPrivateDefault {
private:
HasPrivateDefault() = default;
};

class HasPrivateDefaultAndFriendAccess {
private:
friend class cereal::access;
HasPrivateDefaultAndFriendAccess() = default;
};


#include <iostream>

int main(int, char**)
{
std::cout << "is it default constructible?" << std::endl;
std::cout << std::boolalpha;

std::cout
<< "HasDefault: "
<< cereal::is_default_constructible<HasDefault>::value
<< std::endl;
std::cout
<< "HasNoDefault: "
<< cereal::is_default_constructible<HasNoDefault>::value
<< std::endl;
std::cout
<< "HasPrivateDefault: "
<< cereal::is_default_constructible<HasPrivateDefault>::value
<< std::endl;
std::cout
<< "HasPrivateDefaultAndFriendAccess: "
<< cereal::is_default_constructible<HasPrivateDefaultAndFriendAccess>::value
<< std::endl;

return 0;
}
哪个返回:
is it default constructible?
HasDefault: true
HasNoDefault: false
HasPrivateDefault: false
HasPrivateDefaultAndFriendAccess: true
到目前为止一切都很好。
错误介绍
图书馆 X使用类似的方法来测试给定类是否具有名为 Name的成员变量:
namespace somethingelse {

template <class T>
struct Whatever {
template <class TT> static std::true_type test(decltype(T::Name) *);
template <class TT> static std::false_type test(...);

static constexpr bool value =
std::is_same<decltype(test<T>(nullptr)), std::true_type>::value;
};
}
当我将其添加到文件的顶部时,所有 hell 都松散了。或更确切地说,所有编译仍然可以,但是程序的输出现在更改为:
is it default constructible?
HasDefault: false
HasNoDefault: false
HasPrivateDefault: false
HasPrivateDefaultAndFriendAccess: false
突然,该特征告诉我们,没有什么可以默认构造的……嗯!
可能的“修复”
为了找出正在发生的事情,我更改了代码的某些部分,并找到了两个可能的修复程序,这些修复程序使我们对问题有所了解。
可以通过以下任一方法恢复原始功能:
a)...明确指定测试方法:
static const bool value = std::is_same<decltype(is_default_constructible::test<T>(0)), yes>::value;
要么
b)...将 somethingelse::Whatever::test重命名为 somethingelse::Whatever::test1
实际问题
可悲的是,这两个部分都来自不同的外部库。由于选项b),显然选择了 somethingelse::Whatever::test来获取 cereal::is_default_constructible::value的值。当然这会导致 std::false_type,因为我的测试类没有 Name成员变量。只是使用了错误的测试...
“到底是什么?”
这就是这个问题的标题所在:对我来说,这是不同 namespace 甚至模板类和方法之间的泄漏。我的意思是,由于 WhateverWhatever::test是模板化的,具有不同的模板参数,因此如何推断使用它呢?
如果我添加类似
    typeid(decltype(test<int>(0)));
到我的主要我得到一个编译错误: Use of undeclared identifier 'test'。哪个好对于 cereal::is_default_constructible来说,它不是未声明的,因为它从自己的结构中知道 test,但实际上它再次访问 something::Whatever<T>::test<TT>……不同的 namespace ,不同的模板……
最后的问题
因此,我想知道: 这到底是怎么回事,为什么要这样做呢? 我可能只是不知道这里有一些很酷的c++功能,在这种特殊情况下,这简直让我感到困惑...
所以...请赐教! :)
-尼尔斯
PS:另外,感谢您与我联系并阅读本文墙! :)
PPS:我差点忘了一些规格!
  • Ubuntu 18.04
  • gcc 7.5.0
  • 使用std=gnu++14编译

  • 编辑:较小的示例
    我试图进一步减少问题,并最终解决了这个问题:
    #include <type_traits>

    namespace foo {

    template <class T>
    struct foobaz {
    template <class U> static std::true_type test(U*);

    static constexpr bool value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
    };

    }

    namespace bar {

    template <class T>
    struct barbaz {
    template <class U> static std::true_type test(int);

    static constexpr bool value = std::is_same<std::true_type, decltype(test<T>(0))>::value;
    };

    }

    int main()
    {
    bar::barbaz<int>::value;
    }
    导致编译器错误:
    src/test.cpp: In instantiation of ‘constexpr const bool bar::barbaz<int>::value’:
    src/test.cpp:27:23: required from here
    src/test.cpp:9:84: error: no matching function for call to ‘bar::barbaz<int>::test<int>(std::nullptr_t)’
    static constexpr bool value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
    ~~~~~~~^~~~~~~~~
    src/test.cpp:18:50: note: candidate: template<class U> static std::true_type bar::barbaz<T>::test(int) [with U = U; T = int]
    template <class U> static std::true_type test(int);
    ^~~~
    src/test.cpp:18:50: note: template argument deduction/substitution failed:
    src/test.cpp:9:84: note: cannot convert ‘nullptr’ (type ‘std::nullptr_t’) to type ‘int’
    static constexpr bool value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
    ~~~~~~~^~~~~~~~~
    因此,它尝试通过使用 constexpr const bool bar::barbaz<int>::value表达式来使 constexpr const bool foo:foobaz<???>::value无效。
    这使我确信@DanM是正确的,这是一个编译器错误。

    最佳答案

    我在原始问题中添加了一个较小的示例,该示例为编译器错误提供了更多有关发生问题的信息。好像是@DanM。是正确的,这只是一个编译器错误。可悲的是,我无法在https://gcc.gnu.org/bugzilla上找到它
    因此,答案是:只需使用其他编译器/编译器版本。
    clang 6.0.0和gcc 8.4.0都为我工作。

    关于c++ - C++方法从另一个模板类和 namespace 泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63175835/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com