Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.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++_Templates_C++14_Sfinae_Typetraits - Fatal编程技术网

C++ 如何在C++;?

C++ 如何在C++;?,c++,templates,c++14,sfinae,typetraits,C++,Templates,C++14,Sfinae,Typetraits,我在考虑C++14的隐式模板,并试图声明一个与特定参数类型匹配的函数(SFINAE和traits仍然让我头疼)。我不知道如何解释我想要什么,但我正在尝试做一个简单的解释(只是看看这是否可能,而不是用于生产) 我试图声明一个函数: template<typename T> my_traits<T>::return_type Y(T t) { // ... }; 它可以接受任意数量的参数,但第一个参数应该是具有相同返回类型和相同参数的函数(此函数本身除外)。函子的操作符

我在考虑C++14的隐式模板,并试图声明一个与特定参数类型匹配的函数(SFINAE和traits仍然让我头疼)。我不知道如何解释我想要什么,但我正在尝试做一个简单的解释(只是看看这是否可能,而不是用于生产)

我试图声明一个函数:

template<typename T>
my_traits<T>::return_type Y(T t) {
  // ...
};
它可以接受任意数量的参数,但第一个参数应该是具有相同返回类型和相同参数的函数(此函数本身除外)。函子的
操作符()
的第一个参数是模板

我希望实现的用法:

auto fib = [](auto myself, int x) {
  if(x < 2)
    return 1;
  return myself(x - 1) + myself(x - 2);
};

// The returned type of fib should be assignable to std::function<int(int)>

这是一种非常粗糙的方法,有着严重的局限性,但它是这样的:

首先,我们需要一个假装支持所有可能操作(尽可能)的类,比如类。请注意,这并不是完美的,因为至少
不起作用。为了伪造函子,我们给它一个函数调用操作符:

template<class... Ts> fake_anything operator()(Ts&&...) const;
并添加别名模板以隐藏所有骇客的丑陋之处:

template<class T>
using signature_t = typename extract_signature<decltype(&T::template operator()<fake_anything>)>::type;
模板
使用签名\u t=typename提取\u签名::type;
最后我们可以检查一下

static_assert(std::is_same<signature_t<decltype(fib)>,
                           std::function<int(int)>>::value, "Oops");
static_断言(std::is_same::value,“Oops”);

限制:

  • 必须明确指定
    运算符()
    的返回类型。除非所有
    return
    语句返回相同的类型,而不管functor的返回类型如何,否则不能使用自动返回类型推断
  • 这个假货很不完美
  • 这仅适用于特定形式的
    运算符()
    模板R运算符()(T,参数类型…
    带或不带
    const
    ,其中第一个参数是
    T
    或对可能符合cv条件的
    T
    的引用

在C++14返回类型推断中,不可能按照OP的要求从
int(T,int)
中推断出
int(int)

但是,我们可以使用以下方法屏蔽结果的第一个参数。
struct YCombinator
用一个非递归函数对象成员实例化,该成员的第一个参数是没有第一个参数的自身版本
YCombinator
提供一个调用运算符,该运算符接收非递归函数的参数,然后在替换第一个参数后返回其函数对象成员。这种技术允许程序员避免递归函数定义中
imf(imf,…)
调用的混乱

template<typename Functor>
struct YCombinator
{
    Functor functor;

    template<typename... Args>
    decltype(auto) operator()(Args&&... args)
    {
        return functor(*this, std::forward<Args>(args)...);
    }
};
由于在定义递归函数时未定义非递归函数,因此通常递归函数必须具有显式返回类型

编辑:

但是,在某些情况下,如果程序员在使用非递归函数之前注意指出递归函数的返回类型,编译器可能会推断返回类型。虽然上述构造需要显式返回类型,但在以下GCC 4.9.0中,推导返回类型没有问题:

    auto fib = make_YCombinator([](auto self, int n) { if (n < 2) return 1; return self(n - 1) + self(n - 2); });
-[结束示例]


应用前面注释中的修复,您的
fib
的返回类型被推断为
int
。如果我正确理解Y组合子,它们不会像您所建议的那样返回函数,而是返回参数域中的元素。我遗漏了什么吗?
我自己(x-1)+我自己(x-2)
,就像我写的那样。这就是我的想法。lambda将生成
template int操作符()(T,int)
,我想从中得到
int(int)
。@ThomasMcLeod,Y组合器接受一个非递归函数(其第一个参数是它的一个版本,没有第一个参数)并返回一个递归函数。因此,我试图从
int(T,int)
中推断出
int(int)
。我做了一些非常简单的东西,可以在铿锵中工作,但不能在gcc中工作。我不确定哪一个是正确的:是否有帮助?这样,当您使用
伪类型
-
decltype(&t::template operator())
实例化lambda的
操作符()
时,编译器不应该实例化整个
操作符()
,只有声明,@PiotrS。海湾合作委员会;我不确定哪个编译器是正确的。好的,谢谢,至少,
fake\u anything
的缺陷不会影响ClangI真正喜欢这个答案。
static_assert(std::is_same<signature_t<decltype(fib)>,
                           std::function<int(int)>>::value, "Oops");
template<typename Functor>
struct YCombinator
{
    Functor functor;

    template<typename... Args>
    decltype(auto) operator()(Args&&... args)
    {
        return functor(*this, std::forward<Args>(args)...);
    }
};
template<typename Functor>
decltype(auto) make_YCombinator(Functor f) { return YCombinator<Functor> { f }; }

int main()
{
    auto fib = make_YCombinator([](auto self, int n) -> int { return n < 2 ? 1 : self(n - 1) + self(n - 2); });

    for (int i = 0; i < 10 ; ++i)
        cout << "fib(" << i << ") = " << fib(i) << endl;

    return 0;
}
    auto fib = make_YCombinator([](auto self, int n) { if (n < 2) return 1; return self(n - 1) + self(n - 2); });
auto n = n; // error, n’s type is unknown
auto f();
void g() { &f; } // error, f’s return type is unknown
auto sum(int i) {
if (i == 1)
    return i; // sum’s return type is int
else
    return sum(i-1)+i; // OK, sum’s return type has been deduced
}