gpt4 book ai didi

c++ - 用户定义的转换为模板类引用的编译器行为不一致

转载 作者:行者123 更新时间:2023-11-30 04:54:25 25 4
gpt4 key购买 nike

假设我们有一个模板类 template< typename T> FOO包裹着 T指针,我们希望有一个用户定义的转换来获取 FOO<T const> &指向 FOO 的实例化。下面的重现器代码说明了出现的问题(注意指针转换是为了比较)

#include<iostream>

template< typename T>
class FOO
{
public:
template< typename U=T >
operator typename std::enable_if< !std::is_const<U>::value, FOO<T const> & >::type ()
{
std::cout<<"calling FOO<T>::operator FOO<T const>&()"<<std::endl;
return reinterpret_cast< FOO<T const> &>(*this);
}

template< typename U=T >
operator typename std::enable_if< !std::is_const<U>::value, FOO<T const> * >::type ()
{
std::cout<<"calling FOO<T>::operator FOO<T const>*()"<<std::endl;
return reinterpret_cast< FOO<T const> *>(this);
}

T * m_data = nullptr;
};

int main()
{
FOO<int> foo;

FOO<int const> & fooToConst = foo; // conversion 1r
FOO<int const> & fooToConst2 = static_cast<FOO<int const>&>(foo); // conversion 2r
FOO<int const> & fooToConst3 = foo.operator FOO<int const>&(); // conversion 3r

FOO<int const> * pfooToConst = foo; // conversion 1p
FOO<int const> * pfooToConst2 = static_cast<FOO<int const>*>(foo); // conversion 2p
FOO<int const> * pfooToConst3 = foo.operator FOO<int const>*(); // conversion 3p
return 0;
}

用 gcc8.1.0 编译 g++ -std=c++14 main.cpp一切正常,输出如下:

calling FOO<T>::operator FOO<T const>&()
calling FOO<T>::operator FOO<T const>&()
calling FOO<T>::operator FOO<T const>&()
calling FOO<T>::operator FOO<T const>*()
calling FOO<T>::operator FOO<T const>*()
calling FOO<T>::operator FOO<T const>*()

用clang6.0编译clang++ -std=c++14 main.cpp失败:

main.cpp:29:20: error: non-const lvalue reference to type 'FOO<const int>' cannot bind to a value of unrelated type 'FOO<int>'
FOO<int const> & fooToConst = foo; // conversion 1r
^ ~~~
main.cpp:30:35: error: non-const lvalue reference to type 'FOO<const int>' cannot bind to a value of unrelated type 'FOO<int>'
FOO<int const> & fooToConst2 = static_cast<FOO<int const>&>(foo); // conversion 2r
^ ~~~

所有其他转换(3r、1p、2p、3p)都适用于 clang。

所以问题是...gcc 正确还是 clang 正确?

  • 如果 clang 是正确的,那么转换 (1r,2r) 代码不工作的原因是什么?

    • 我知道指针转换有点古怪,但为什么 (1p, 2p) 被接受,而 (1r, 2r) 不被接受?
    • 为什么 gcc 允许它们?
  • 如果 gcc 是正确的,这是 clang 中的错误吗?

编辑如果 (1r,2r) 的转换尝试更改为:

FOO<int const> const & fooToConst  = foo;                                      // conversion 1r
FOO<int const> const & fooToConst2 = static_cast<FOO<int const> const&>(foo); // conversion 2r

这一切都适用于 clang!为什么会这样?

最佳答案

这个“答案”解决了实际问题,而不是哪个(clang 或 gcc)是正确的。我将它包括在内,因为它可能对 OP 有帮助,即使它对于 来说还不够好。在这一点上回答。

template<class X>
struct get_template_arg0;
template<class X>
using get_template_arg0_t=typename get_template_arg0<X>::type;

template<template<class...>class Z, class T>
struct get_template_arg0<Z<T>> {
using type=T;
};

template< typename T>
class FOO
{
public:
template< typename U,
std::enable_if_t<
std::is_same<std::remove_const_t<get_template_arg0_t<U>>, T>{}
&& !std::is_same<get_template_arg0_t<U>, T>{},
bool
> =true
>
operator U& ()
{
std::cout<<"calling FOO<T>::operator FOO<T const>&()"<<std::endl;
return reinterpret_cast< FOO<T const> &>(*this);
}

template< typename U,
std::enable_if_t<
std::is_same<std::remove_const_t<get_template_arg0_t<U>>, T>{}
&& !std::is_same<get_template_arg0_t<U>, T>{},
bool
> =true
>
operator U*()
{
std::cout<<"calling FOO<T>::operator FOO<T const>*()"<<std::endl;
return reinterpret_cast< FOO<T const> *>(this);
}

T * m_data = nullptr;
};

我简化了模板转换运算符中的类型推导,然后添加了 SFINAE 测试。

clang++ 和 g++ compile this "correctly" .

(正如其他人所指出的,您的 reintepret_cast 使程序表现出未定义的行为。)

关于c++ - 用户定义的转换为模板类引用的编译器行为不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53599581/

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