Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.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++14编译苹果的Clang8.1.0版本。下面是说明问题的工作代码_C++_C++14_Metaprogramming_Template Meta Programming - Fatal编程技术网

C+的问题+;用于检测函数是否存在的元函数 我有一个问题,我不理解C++元函数。我正在使用C++14编译苹果的Clang8.1.0版本。下面是说明问题的工作代码

C+的问题+;用于检测函数是否存在的元函数 我有一个问题,我不理解C++元函数。我正在使用C++14编译苹果的Clang8.1.0版本。下面是说明问题的工作代码,c++,c++14,metaprogramming,template-meta-programming,C++,C++14,Metaprogramming,Template Meta Programming,我从其他地方抄袭了一个元函数,我正在尝试使用它。它旨在检测名为“bananify”的函数,这些函数具有传递给元函数的类型的参数。你称之为 BananifyDetector<int>::value 问题是,它只在被搜索的函数在BananifyFinder的模板定义之前声明时才起作用,而不是它的实例化。因此,在我的示例代码中,我希望这两个 BananifyFinder<int> BananifyFinder<std::string> BananifyFin

我从其他地方抄袭了一个元函数,我正在尝试使用它。它旨在检测名为“bananify”的函数,这些函数具有传递给元函数的类型的参数。你称之为

BananifyDetector<int>::value 
问题是,它只在被搜索的函数在BananifyFinder的模板定义之前声明时才起作用,而不是它的实例化。因此,在我的示例代码中,我希望这两个

BananifyFinder<int>
BananifyFinder<std::string> 
BananifyFinder
BananifyFinder
成功地使用下面的代码,但由于定义了bananify(std::string)的位置,它失败了

这是令人沮丧的,就像我把函数检测器放在头文件中一样,我必须在客户机代码中包含顺序感知,这是一个巨大的痛苦,在某些情况下可能不可能正确

我不知道这里发生了什么。它是C++的特性,还是一个笨拙的bug?还是我做的蠢事? 谢谢你的帮助

#include <iostream>
#include <type_traits>   
////////////////////////////////////////////////////////////////////////////////
// A bananify function to be detected
// This is successfully found.
double bananify(int)
{
  return 0.0;
}

/// A meta function that detects if a single argument function named 'bananify'
/// exists with takes an argument of the type passed to the metafunction.
///
/// Note, automatic casts will get in the way occasionally so if function
/// bananify(float) exists, a BananifyFinder<int>::value will return true.
template<class ARG1>
class BananifyFinder {
private :
  template<typename ...> using VoidT_ = void;

  template<typename A1, typename = void>
  struct Test_ : std::false_type
  {
    typedef void returnType;
  };

  template<typename A1>
  struct Test_<A1, VoidT_<decltype(bananify(std::declval<A1>()))>> : std::true_type
  {
    typedef decltype(bananify(std::declval<A1>())) returnType;
  };

public :
  typedef typename Test_<ARG1>::returnType returnType;
  constexpr static bool value = Test_<ARG1>::value;
};

////////////////////////////////////////////////////////////////////////////////
// A bananify function to be detected that takes std::strings
// This fails to be found, but if we move it before the declaration of BananifyFinder it
// will be found;
std::string bananify(std::string)
{
  return "s";
}

// dummy class with no bananify function to be found
class Nothing{};

// check the results of the metafunction 'T'
template<class T>
void CheckBanana(const std::string &str)
{
  using DetectedType = BananifyFinder<T>;
  std::cout << str << " detected is " << DetectedType::value << std::endl;
  std::cout << str << " returns is " << typeid(typename DetectedType::returnType).name() << std::endl << std::endl;
}

////////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
  // this should print "BananifyFinder<int> 1 d"
  CheckBanana<int>("BananifyFinder<int> ");

  // this should print "BananifyFinder<std::string>  1 NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE"
  // but it prints "BananifyFinder<std::string>  0 v"
  // FAILS
  CheckBanana<std::string>("BananifyFinder<std::string> ");

  // this should print "BananifyFinder<Nothing>  0 v"
  CheckBanana<Nothing>("BananifyFinder<Nothing> ");
}
#包括
#包括
////////////////////////////////////////////////////////////////////////////////
//要检测的bananify函数
//这已成功找到。
双bananify(int)
{
返回0.0;
}
///一种元函数,用于检测名为“bananify”的单参数函数
///exists with接受传递给元函数的类型的参数。
///
///请注意,自动强制转换有时会妨碍功能的正常运行
///如果存在BananifyFinder::值,BananifyFinder::值将返回true。
模板
类BananifyFinder{
私人:
使用void的模板t=void;
模板
结构测试:std::false\u类型
{
类型定义无效返回类型;
};
模板
结构测试:std::true\u类型
{
typedef decltype(bananify(std::declval())returnType;
};
公众:
typedef typename测试\::returnType returnType;
constexpr静态布尔值=测试值;
};
////////////////////////////////////////////////////////////////////////////////
//要检测的bananify函数,它接受std::strings
//这无法找到,但如果我们在BananifyFinder声明之前移动它
//将被发现;
std::string bananify(std::string)
{
返回“s”;
}
//找不到bananify函数的伪类
类Nothing{};
//检查元函数“T”的结果
模板
void CheckBanana(const std::string和str)
{
使用DetectedType=BananifyFinder;

std::cout模板分两个阶段进行解析

在第一种方法中,解析独立于模板参数的表达式。在第二种方法中,解析与模板相关的参数依赖项

decltype(bananify(std::declval

ADL检查具有外部链接的函数声明 在模板定义上下文和模板中都可见 实例化上下文(换句话说,添加一个新函数 模板定义后的声明不会使其可见,除非 通过ADL)

因此,您的代码查看
std::
(使用ADL)并没有找到
bananify
函数


在模板实例化之前移动它就足以使其符合查找条件。

我认为
bananify
引用在实例化之前在模板中得到解析,因为它不是依赖的。因此,不会看到未声明的重写

通常,您希望搜索作为类型成员可用的函数,而不是在顶级,在这种情况下,问题消失了:

#include <iostream>
#include <type_traits>
#include <typeinfo>

class A {
  public:
  double bananify(int)
  {
    return 0.0;
  }
};

// Find bananify(ARG1) as a member of C:
template<class C, class ARG1>
class BananifyFinder {
private :
  template<typename ...> using VoidT_ = void;

  template<typename A1, typename = void>
  struct Test_ : std::false_type
  {
    typedef void returnType;
  };

  template<typename A1>
  struct Test_<A1, VoidT_<decltype(std::declval<C>().bananify(std::declval<A1>()))>> : std::true_type
  {
    typedef decltype(std::declval<C>().bananify(std::declval<A1>())) returnType;
  };

public :
  typedef typename Test_<ARG1>::returnType returnType;
  constexpr static bool value = Test_<ARG1>::value;
};

class B {
  public:
  std::string bananify(std::string)
  {
    return "s";
  }
};


// check the results of the metafunction 'T'
template<class C, class T>
void CheckBanana(const std::string &str)
{
  using DetectedType = BananifyFinder<C,T>;
  std::cout << str << " detected is " << DetectedType::value << std::endl;
  std::cout << str << " returns is " << typeid(typename DetectedType::returnType).name() << std::endl << std::endl;
}


int main(int argc, char *argv[])
{
  CheckBanana<A,int>("BananifyFinder<int> "); // ok
  CheckBanana<B,std::string>("BananifyFinder<std::string> "); // ok
}
#包括
#包括
#包括
甲级{
公众:
双bananify(int)
{
返回0.0;
}
};
//查找bananify(ARG1)作为C的成员:
模板
类BananifyFinder{
私人:
使用void的模板t=void;
模板
结构测试:std::false\u类型
{
类型定义无效返回类型;
};
模板
结构测试:std::true\u类型
{
typedef decltype(std::declval().bananify(std::declval())returnType;
};
公众:
typedef typename测试\::returnType returnType;
constexpr静态布尔值=测试值;
};
B类{
公众:
std::string bananify(std::string)
{
返回“s”;
}
};
//检查元函数“T”的结果
模板
void CheckBanana(const std::string和str)
{
使用DetectedType=BananifyFinder;

std::cout其他人留下了答案,但似乎已被删除。这是一个与模板名称相关的查找问题

地址在这里


这里的更多细节

为了正确起见,
banify(std::string)
需要声明(而不是定义)在检测到模板
BananifyFiner
之前。在使用
#include
之前,您是否希望能够使用
std::vector
?这就是这里发生的事情。AndyG,这更像是在使用MyClass之前必须声明MyClass。@brunobignose:不完全是……我想我需要写一个答案。a与姓名相关的查找问题。我在编辑时“暂停”了我的查找以澄清问题。我在编辑时“暂停”了查找以澄清问题。
#include <iostream>
#include <type_traits>
#include <typeinfo>

class A {
  public:
  double bananify(int)
  {
    return 0.0;
  }
};

// Find bananify(ARG1) as a member of C:
template<class C, class ARG1>
class BananifyFinder {
private :
  template<typename ...> using VoidT_ = void;

  template<typename A1, typename = void>
  struct Test_ : std::false_type
  {
    typedef void returnType;
  };

  template<typename A1>
  struct Test_<A1, VoidT_<decltype(std::declval<C>().bananify(std::declval<A1>()))>> : std::true_type
  {
    typedef decltype(std::declval<C>().bananify(std::declval<A1>())) returnType;
  };

public :
  typedef typename Test_<ARG1>::returnType returnType;
  constexpr static bool value = Test_<ARG1>::value;
};

class B {
  public:
  std::string bananify(std::string)
  {
    return "s";
  }
};


// check the results of the metafunction 'T'
template<class C, class T>
void CheckBanana(const std::string &str)
{
  using DetectedType = BananifyFinder<C,T>;
  std::cout << str << " detected is " << DetectedType::value << std::endl;
  std::cout << str << " returns is " << typeid(typename DetectedType::returnType).name() << std::endl << std::endl;
}


int main(int argc, char *argv[])
{
  CheckBanana<A,int>("BananifyFinder<int> "); // ok
  CheckBanana<B,std::string>("BananifyFinder<std::string> "); // ok
}