gpt4 book ai didi

c++ - 基于 SFINAE 的特征来确定是否支持运算符 +

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

你好我使用模板在 C++ 中编写代码,并尝试实现一个 SFINAE,当运算符 + 时被触发。不支持。我写了下面的代码

#include <iostream>
#include <type_traits>
class B
{
};
template<typename T1,typename T2>
struct IsSameT :std::false_type
{
//static constexpr bool value = false;
};

template<typename T>
struct IsSameT<T,T> :std::true_type
{
//static constexpr bool value = true;
};
template<typename T1, typename T2>
struct HasPlusT
{
private:
using T1_t = typename std::remove_reference<T1>::type;
using T2_t = typename std::remove_reference<T2>::type;
template<typename U1, typename = decltype(T1_t() + T2_t())>
static char test(void *);
template<typename>
static long test(...);
public:
static constexpr bool value = IsSameT<decltype(test<T1,T2>(nullptr)),char>::value;
};

template<typename T1,typename T2, bool = HasPlusT<T1,T2>::value>
struct PlusResultT
{
using T1_t = typename std::remove_reference<T1>::type;
using T2_t = typename std::remove_reference<T2>::type;
using Type = decltype(T1_t() + T2_t());
};

template<typename T1,typename T2>
struct PlusResultT<T1,T2,false>
{
using T1_t = typename std::remove_reference<T1>::type;
using T2_t = typename std::remove_reference<T2>::type;
using Type = decltype(T1_t() + T2_t());
};


int main()
{

constexpr bool value = HasPlusT<B,B>::value;
return 0;
}

我希望 constexpr bool value = HasPlusT<B,B>::value返回 false但产生了一个错误执行中有什么问题?

Class B has not an operator + and I expect that the constexpr bool value = >HasPlusT::value returns true. However a compilation error is generated no match for 'operator+' (operand types are 'HasPlusT::T1_t {aka B}' and >'HasPlusT::T2_t {aka B}') Demo.cpp /Demo C/C++ >Problem

==============================================

支持类模板的新实现。为什么以下实现无法验证运算符 + 是否存在

#include <iostream>
#include <type_traits>
#include <array>
#include <vector>
#include <utility>

template<typename T1,typename T2>
struct IsSameT :std::false_type
{
//static constexpr bool value = false;
};

template<typename T>
struct IsSameT<T,T> :std::true_type
{
//static constexpr bool value = true;
};

template<typename T, typename U>
struct IsFuntamentalHelper : IsSameT<T,U>
{
//static constexpr bool value = IsSameT<T,U>::value;
};
template<typename T>
struct IsFundamentalT : std::false_type
{
//static constexpr boo value = std::false_type;
};

template<>
struct IsFundamentalT<int> : IsFuntamentalHelper<int,int>
{

};
template<>
struct IsFundamentalT<float> : IsFuntamentalHelper<float,float>
{

};
template<>
struct IsFundamentalT<double> : IsFuntamentalHelper<double,double>
{

};
template<>
struct IsFundamentalT<long>: IsFuntamentalHelper<long,long>
{

};

template<typename T>
using enable_if_t = typename std::enable_if<IsFundamentalT<T>::value, T>::type;

template<typename T>
class A
{
public:
template<typename = enable_if_t<T>>
operator T()
{
return t ;
}
A<T>():t()
{

}
template<typename = enable_if_t<T>>
A<T>(T a)
{
std::cout << "integer" << std::endl;
this->t = a;
}
A<T>(A<T> const & a)
{
this->t = a.t;

}
public:
A<T> add(A<T> & a)
{
t += a.t;
return *this;

}
friend A<T> operator + (A<T> & a1, A<T> & a2)
{

return a1.add(a2);
}
T t;
};
template<typename T1, typename T2>
struct HasPlusT
{
private:
template <typename T>
using Rr = typename std::remove_reference<T>::type;

template<typename U1, typename U2>
static auto test(void *)
-> decltype(std::declval<Rr<U1>>() + std::declval<Rr<U2>>() , '0');

template<typename...>
static long test(...);

public:
static constexpr bool value
= IsSameT<decltype(test<T1,T2>(nullptr)),char>::value;
};


template<typename T1,typename T2, bool = HasPlusT<T1,T2>::value>
struct PlusResultT
{
using T1_t = typename std::remove_reference<T1>::type;
using T2_t = typename std::remove_reference<T2>::type;
using Type = decltype(T1_t() + T2_t());
};

template<typename T1,typename T2>
struct PlusResultT<T1,T2,false>
{
using T1_t = typename std::remove_reference<T1>::type;
using T2_t = typename std::remove_reference<T2>::type;
using Type = decltype(T1_t() + T2_t());
};


int main()
{
constexpr bool value = HasPlusT<A<int>,A<int>>::value;
std::cout << value << std::endl;


return 0;
}

最佳答案

尝试

template <typename T1, typename T2>
struct HasPlusT
{
private:
template <typename T>
using Rr = typename std::remove_reference<T>::type;

template<typename U1, typename U2>
static auto test(void *)
-> decltype(std::declval<Rr<U1>>() + std::declval<Rr<U2>>() , '0');

template<typename...>
static long test(...);

public:
static constexpr bool value
= IsSameT<decltype(test<T1,T2>(nullptr)),char>::value;
};

我的意思是...您的代码有几个问题。

排名不分先后。

1 - 如果您调用 test<T1,T2>(nullptr) ,您显式传递了两个模板类型;所以如果你定义 test第二个参数有第二种类型

template<typename U1, typename = decltype(T1_t() + T2_t())>
static char test(void *);

第二个从未使用过。

2 - SFINAE 使用函数的模板参数;不使用类的模板参数。所以如果你尝试做一些事情

template<typename U1, typename U2, typename = decltype(T1_t() + T2_t())>
static char test(void *);

SFINAE 不起作用,因为您没有使用 U1U2 (方法的模板参数)但带有 T1_t()T2_t() , 所以 T1T2 , 类的模板参数。

所以我建议使用 using Rr删除引用

      template <typename T>
using Rr = typename std::remove_reference<T>::type;

并且,为了更简单,通过返回类型使用 SFINAE

  template<typename U1, typename U2>
static auto test(void *)
-> decltype(std::declval<Rr<U1>>() + std::declval<Rr<U2>>() , '0');

-- 编辑 --

OP 无法使用 std::declval() .

I use mingw and for an unknown reason cannot recognize declval

所以我提出了一个胜于无的简单替代品(没有 std::add_rvalue_reference<T>::type ,以防你不能使用它)

template <typename T>
T declVal();

HasPlusT成为

template <typename T1, typename T2>
struct HasPlusT
{
private:

template <typename T>
using Rr = typename std::remove_reference<T>::type;

template<typename U1, typename U2>
static auto test(void *)
-> decltype(declVal<Rr<U1>>() + declVal<Rr<U2>>() , '0');

template<typename...>
static long test(...);

public:
static constexpr bool value
= IsSameT<decltype(test<T1,T2>(nullptr)),char>::value;
};

-- 编辑 2 --

OP 说

what modifications are needed to support check for class templates? I try to do this for a class A but seems not to work. See in the initial post.

不是类模板的问题。

问题是你的 operator+()对于 A

friend A<T> operator + (A<T> & a1, A<T> & a2)
{ return a1.add(a2); }

是不寻常的,因为它(正确地)是一个 friend类的函数,但接收对 A<T> 的引用(左引用),而不是常量对象(通常是 const 引用;第一个值可以是未引用的值),修改第一个接收到的参数(危险)并通过拷贝返回。

所以 HasPlusT类(class)失败,因为 std::declval()返回与 operator+ 不匹配的右值引用对象要求 l 值。

强烈建议您修改operator+()如下( a1a2 const )

  friend A<T> operator+ (A<T> const & a1, A<T> const & a2)
{ A<T> ret{a1}; return ret.add(a2); }

或者,也许更好,如下所示( a1 没有 &a2 const )

  friend A<T> operator+ (A<T> a1, A<T> const & a2)
{ return a1.add(a2); }

你会看到 HasPlusT再次工作。

关于c++ - 基于 SFINAE 的特征来确定是否支持运算符 +,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51994788/

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