Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 调用自由函数而不是方法(如果没有';不存在_C++_Templates_C++11 - Fatal编程技术网

C++ 调用自由函数而不是方法(如果没有';不存在

C++ 调用自由函数而不是方法(如果没有';不存在,c++,templates,c++11,C++,Templates,C++11,假设有一系列类型无关的类通过返回值的给定方法实现了一个公共概念: class A { public: int val() const { ... } }; class B { public: int val() const { ... } }; 假设您需要一个泛型自由函数,该函数使用T为任何类型返回常规值,而不实现val方法,或者为所有具有一个方法的类型调用val方法: template<class T> int val_of(const T& t) { return 0;

假设有一系列类型无关的类通过返回值的给定方法实现了一个公共概念:

class A { public: int val() const { ... } };
class B { public: int val() const { ... } };
假设您需要一个泛型自由函数,该函数使用
T
为任何类型返回常规值,而不实现
val
方法,或者为所有具有一个方法的类型调用
val
方法:

template<class T> int val_of(const T& t) { return 0; }
template<class T> int val_of(const T& t) { return t.val(); }
template int val_of(const T&T){return 0;}
模板int val_of(const T&T){return T.val();}
假设A和B只是示例:您不知道有多少类型将实现
val
,有多少类型将不实现它(因此显式专门化不会扩展)

有没有一种基于C++标准的简单方法,可以静态选择< <代码> >版本> < >p>


我正在考虑一个
std::conditional
std::enable_if
,但我没有找到一个简单的方法来表示条件。

您可以使用返回类型SFINAE:

template<typename T>
auto val_of(const T& t) -> decltype(std::declval<T>().val())
{
    return t.val();
}

int val_of(...)
{
    return 0;
}
模板
自动赋值(const T&T)->decltype(std::declval().val())
{
返回t.val();
}
(…)的int val_
{
返回0;
}

使用此类型特征类确定类型是否具有
val
成员函数

template<typename U>
struct has_val {
    typedef char yes;
    typedef struct { char c[2]; } no;

    template<typename X>
    static constexpr auto test(int) -> decltype( std::declval<X>().val(), yes() );

    template<typename X>
    static constexpr no test(...);

    static constexpr bool value = sizeof(test<U>(0)) == sizeof(yes);
};
模板
结构具有{
typedef char是;
typedef结构{char c[2];}no;
模板
静态constexpr自动测试(int)->decltype(std::declval().val(),yes());
模板
静态常数无试验(…);
静态constexpr bool value=sizeof(测试(0))==sizeof(是);
};

如果

只是一个稍长的注释,您可以将其用作启用\u的条件。。。你的问题已经回答了。但我最近也遇到了类似的问题。假设您想编写一个方法将字符串打印到
cout
:使用成员函数
write(std::cout)
,如果不可用,则使用自由函数
到字符串()
,如果不可用,则返回到
操作符decltype(std::cout当前投票率最高的答案在某些情况下会调用未定义的行为,因此我将给出另一个答案

我们从一些样板机器开始:

template<typename T> struct type_sink { typedef void type; }
template<typename T> using TypeSink = typename type_sink<T>::type;
然后,我们可以使用标签调度来解决您的问题:

template<typename T>
int val_of_internal( T const& t, std::true_type /* has_val */ ) {
  return t.val();
}
template<typename T>
int val_of_internal( T const& t, std::false_type /* has_val */ ) {
  return 0;
}
template<typename T>
int val_of( T const& t ) {
  return val_of_internal( t, has_val<T const>() );
}
现在我们可以这样写:

HAS_NULLARY_METHOD_TRAIT( has_val, val );

但是我不知道它是否值得。

但是这是两个不同的功能,我认为OP需要一个function@Paranaix:这没关系,直到给定的T中只有一个可以存在,但是……我知道当第一个无法实例化时,第二个可以存在,但是当它成功时,两个都可以存在。第一个如何优先?,尽管如此。@MooingDuck:我认为这与省略号扩展中的隐式转换序列有关(而函数模板中的参数不需要转换)我不明白你的问题。什么是
状态
方法?什么是
的值?
的第二句话是什么意思?@LightnessRacesinOrbit:对不起,只是一个命名错误:请参见编辑。有没有办法(可能只有在编译器宏的帮助下)将其推广到
具有成员函数
(也就是说,
有_member_function
或类似的功能)?@elemakil恐怕你只能用普通的旧宏来做。哇……有趣……这是一个真正需要研究的东西!很棒的技巧。如果你感兴趣,你可以概括一下,并为这个问题写一个答案:这不是我的技巧……:(IIRC,我是从std::advance学习到这个的。我刚刚补充了这个作为你问题的答案。
template<typename T>
int val_of_internal( T const& t, std::true_type /* has_val */ ) {
  return t.val();
}
template<typename T>
int val_of_internal( T const& t, std::false_type /* has_val */ ) {
  return 0;
}
template<typename T>
int val_of( T const& t ) {
  return val_of_internal( t, has_val<T const>() );
}
#define EXPRESSION_IS_VALID_FOR_TYPE_T_TRAIT( TRAIT_NAME, ... ) \
template<typename T, typename=void> \
struct TRAIT_NAME : std::false_type {}; \
template<typename T> \
struct TRAIT_NAME< T, TypeSink< decltype( __VA_ARGS__ ) > >: std::true_type {}

#define HAS_NULLARY_METHOD_TRAIT(TRAIT_NAME, METHOD_NAME) \
EXPRESSION_IS_VALID_FOR_TYPE_T_TRAIT( TRAIT_NAME, std::declval<T>().METHOD_NAME() )
HAS_NULLARY_METHOD_TRAIT( has_val, val );