当前位置: 首页 > 知识库问答 >
问题:

转换函数,std::is_base_和伪不完整类型:替换失败是一个错误

凌昕
2023-03-14

我试图实现一个转换函数操作符,并使用std::is_base_of来限制适用范围,但我遇到了一些问题。

#include <type_traits>

class Spurious;

class MyClassBase {};

template< typename T >
class MyClass: public MyClassBase {
public:
    template< typename U, std::enable_if_t< std::is_base_of<MyClassBase, U>::value, bool> = true >
    operator U () const {
        return U{}; // Complex initialization omitted for brevity
    }
};

class MyBool: public MyClass< bool > {};
class MyInt: public MyClass< int > {};

int do_stuff( int i, Spurious const & obj);
int do_stuff( int i, MyBool const & obj) {
    return i;
}

int main() {
    MyInt const obj;
    return do_stuff( 3, obj );
}

Spurouse和相关函数定义的存在意味着我在实现的基础中遇到了编译器错误(编译器资源管理器;GCC:错误:不完整类型“const class spurouse”的使用无效。Clang:错误:类型特征表达式中使用的不完整类型“spurouse”)。

我明白为什么你不能是一个不完整的类型,但我不太明白为什么“替换失败不是错误”在这里不适用。我本以为,在模板扩展过程中,试图将is_base_定义为不完整的类型会导致编译器中止转换尝试,并继续下一个函数定义。这就是这里is_base_of语句的全部要点:忽略与模式不匹配的类。

不过,我的主要问题不是“为什么”,而是“下一步做什么”。有什么变通办法吗?有没有办法忽略像Spurous这样的东西,同时不要求它们在这个编译单元中完全定义?理想情况下,我只需修改转换运算符的定义(例如SFINAE模板参数)即可使其工作。


共有1个答案

贾成天
2023-03-14

这不是SFINAE,它当然适用于不完整的类型:

template<class T,bool=false>
struct size : std::integral_constant<std::size_t,0> {};
template<class T>
struct size<T,!sizeof(T)> : std::integral_constant<std::size_t,sizeof(T)> {};
static_assert(size<char>::value==1);  // OK

struct A;
static_assert(size<A>::value==0);  // OK
struct A {};
static_assert(size<A>::value==0);  // OK!

这里的问题是,如果两种类型都是非联合类类型,且后者不完整,那么std::is_base_of具有“未定义的行为”(阅读:使用它会使程序格式错误,不需要诊断)。SFINAE没有涵盖这一点,因为它不在直接上下文中,也因为它是NDR。

这些编译器选择拒绝代码,这样做的好处是防止出现类似//OK 以上。

您可以使用直接SFINAE方法来避免此问题:

template< typename T >
class MyClass: public MyClassBase {
public:
    template< typename U, std::enable_if_t<
        (sizeof(U), std::is_base_of<MyClassBase, U>::value), bool> = true >
    operator U () const {
        return U{}; // Complex initialization omitted for brevity
    }
};

如果U不完整,则模板参数的类型中存在直接替换错误,这会阻止实例化将成为IFNDR的std::is_base_的specialization。请注意,以这种方式将不完整类型与SFINAE一起使用仍然相当危险,因为在相关类型完整的上下文中实例化的相同专门化可能会产生不同的行为(这也是IFNDR,per[temp.point]/7)。

 类似资料:
  • 问题内容: 我有一个代码段: 为什么不自动类型转换为while ? 问题答案: 因为是,并且具有更大的范围。因此,将其分配给可能会导致数据丢失。 是一个常数,而编译时间保证在的范围内。

  • 在模板成员函数中使用std::function时出现编译错误,下面的代码是一个简单的示例: 我用的是C++11和G++4.7

  • 在对服务的请求中,有十几个属性,其中两个是JSON数组。在我从转换器获得的openapi.json文件中,它们显示为 那么,是OpenAPI规范缺少了数组定义,还是转换器做错了,我需要用其他东西替换items token?如果是的话,是哪一个?

  • 问题内容: 我在代码隐藏中收到转换失败的错误。我的代码如下: 我收到以下错误: 将nvarchar值转换为数据类型int时,转换失败。 在这里必须进行哪些更改? 问题答案: 我想这是一个整数,但您正在分配一个字符串。因此,这可能会解决它: 编辑:由于您已评论该会话存储了用户名,但该列是一个int列,因此您有三个选择: 更改会话以存储用户标识而不是名称 更改列以存储用户名 从存储用户名的表中选择用户

  • 问题内容: 我创建了一个过程并收到了此消息 将varchar值’%’转换为数据类型int时,转换失败。 我不知道这可能是什么,但是当我将过程更改为这样时: 似乎工作正常。我是SQL的新手,所以可以得到任何帮助,也许有更好的方法来做我想做的事情? 问题答案: 这是在子句中: 是一个整数。因此,您需要将其转换为字符串: 为什么要使用称为的列是可疑的。也许您只想要: