Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.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++_C++11_Templates_Sfinae_Typetraits - Fatal编程技术网

C++ 有没有一种方法可以得到一个对象的函数是否存在的否定?

C++ 有没有一种方法可以得到一个对象的函数是否存在的否定?,c++,c++11,templates,sfinae,typetraits,C++,C++11,Templates,Sfinae,Typetraits,要确定函数是否存在,可以使用以下命令: template <typename...Ts> using void_t = void; void fn(int); struct X {}; template <typename T, typename = void_t<decltype(fn(std::declval<T>()))>> void fn2(T) { } void test() { fn2(int(1)); // works

要确定函数是否存在,可以使用以下命令:

template <typename...Ts>
using void_t = void;

void fn(int);

struct X {};

template <typename T, typename = void_t<decltype(fn(std::declval<T>()))>>
void fn2(T) { }

void test() {
  fn2(int(1)); // works
  //fn2(X()); // doesn't work
}

这样做的原因是定义一个排除操作,这样我就可以为这两个操作定义
fn2()
,以避免出现歧义错误。

您需要另一个
fn2
重载,否则SFINAE将不会做任何有用的事情

void fn2(...) { } // called if the overload below is SFINAEd away

template <typename T, typename = void_t<decltype(fn(std::declval<T>()))>>
void fn2(T) { }
void fn2(…){}//如果下面的重载被忽略,则调用
模板
void fn2(T){}



其思想是SFINAE可以从重载集中删除候选对象。如果
fn2
是唯一的候选者,那么你将得到一个硬错误。

通常的做法是创建一个类型特征,如@chris所说:

template <typename T, typename = void>
struct fn_callable_with : std::false_type {};
template <typename T>
struct fn_callable_with<T, void_t<decltype(fn(std::declval<T>()))>> : std::true_type {};

// For bonus C++14 points:
// template <typename T>
// /*C++17: inline*/ constexpr bool fn_callable_with_v = fn_callable_with<T>::value;

template <typename T, typename = typename std::enable_if<!fn_callable_with<T>::value>::type>
// C++14: template <typename T, typename = std::enable_if_t<!fn_callable_with_v<T>>>
void fn2(T) { }
模板
结构fn_可调用_,类型为:std::false_{};
模板
结构fn_callable_with:std::true_type{};
//对于C++14点的奖励:
//模板
///*C++17:inline*/constexpr bool fn_callable_with_v=fn_callable_with::value;
模板::类型>
//C++14:模板>
void fn2(T){}

我建议将该复选框包装为类型特征。那么否定与任何其他特征都是一样的。@Quentin,fixedaaaa和:|它在没有
void\t
的情况下工作得很好。@Quentin,是的,耸耸肩。我现在不担心克朗的虫子@kabanus,编辑答案以回答您的问题。是的,我确实需要重载它,但当它与已定义的不匹配时,我需要重载它。换句话说,我需要定义一个排除操作,这样我就不会出现歧义错误,同时又不会导致硬错误并保留类型。@Adrian,如果您试图重载已经实现的方法,您的意思是想得到编译时错误吗?没有编译时错误。如果一个函数可以在一个对象上操作,我想要一种选择函数的方法,如果不能,我想要选择另一个函数。我刚刚被咬了一口:这并不是在所有情况下都有效
fn
decltype
探测中是一个依赖名称,因此它的查找被推迟到模板的实例化,这是我们需要的。但是,查找必须通过ADL找到
fn
。这意味着,如果基本类型的
fn
,以及来自其他名称空间的
fn
,在模板专门化之前尚未声明,则不会检测到它们@昆汀——OP自己的代码在模板定义之前方便地定义了
void fn(int)
。这样就可以找到一个。你所描述的只是模板的一般警告,没有什么新鲜事。@StoryTeller只是期待最坏的结果;)@昆汀——应该这样说:)顺便说一句,在你发布的链接中,我认为你发现了编译器错误。这两个
fn
不应该被找到,但他们似乎被找到了。@StoryTeller,天哪,他们没有子弹了吗?这是我这辈子见过的最毛茸茸的句子。
template <typename T, typename = void>
struct fn_callable_with : std::false_type {};
template <typename T>
struct fn_callable_with<T, void_t<decltype(fn(std::declval<T>()))>> : std::true_type {};

// For bonus C++14 points:
// template <typename T>
// /*C++17: inline*/ constexpr bool fn_callable_with_v = fn_callable_with<T>::value;

template <typename T, typename = typename std::enable_if<!fn_callable_with<T>::value>::type>
// C++14: template <typename T, typename = std::enable_if_t<!fn_callable_with_v<T>>>
void fn2(T) { }