gcc 4.7 关于可变参数模板/ decltype /std::forward.

gcc 4.7 about Variadic Templates/ decltype /std::forward

本文关键字:forward decltype std 于可变 参数 gcc      更新时间:2023-10-16
    char foo()
    {
         std::cout<<"foo()"<<std::endl;
         return 'c';
    }              
    void foo(char &&i)
    {
         std::cout<<"foo(char &&i)"<<std::endl;
    }
    struct pipe {};
    template<class OP>
    struct Flow;
    template<>
    struct Flow<pipe> {
         template<class L,class R>
         static  auto apply(L&& l,R &&r)->decltype(r(std::forward<L>(l))) {
              return r(std::forward<L>(l));
         }
    };
    template<class L,class R,class E>
    struct Pipe;
    template<class F,class...ARGS>
    auto eval(F& f,ARGS&&... arg)->decltype(f(std::forward<ARGS>(arg)...))
    {
        return f(std::forward<ARGS>(arg)...);
    }
    template<class L,class R,class E,class...ARGS>
    auto eval(Pipe<L,R,E>&f,ARGS&&... arg)->decltype(Flow<E>::apply(eval(f.lhs,std::forward<ARGS>(arg)...),f.rhs))
    {
        return Flow<E>::apply(eval(f.lhs,std::forward<ARGS>(arg)...),f.rhs);
    }
    template<class L,class R,class E>
    struct Pipe {
         L lhs;
         R rhs;
         Pipe(L &l,R& r):lhs(l),rhs(r) {
         }
          template<class...ARGS>
           auto operator()(ARGS&&... arg)->decltype(eval<L,R,E >(*this,std::forward<ARGS>(arg)...)) {
                return eval<L,R,E >(*this,std::forward<ARGS>(arg)...);
           }
    };
     void streamtest()
    {
        void (*foo1)(char &&)=foo;
        void (*foo2)(int ,int ,short )=foo;
        char (*foo3)()=foo;
        Pipe<char(*)(),void(*)(char&&),pipe> pp(foo3,foo1);
        pp(1);
    }

我想写一个用于函数传输的管道库。 但错误 让我感到困惑:

 FEstream.cpp: In function 'void streamtest()':
 FEstream.cpp:117:9: error: no match for call to '(Pipe<char (*)(), void (*)(char&&), pipe>) (int)'
 FEstream.cpp:98:8: note: candidate is:
 FEstream.cpp:104:13: note: template<class ... ARGS> decltype (eval<L, R, E>((* this), (forward<ARGS>)(Pipe::operator()::arg)...)) Pipe::operator()(ARGS&& ...) [with ARGS = {ARGS ...}; L = char (*)(); R = void (*)(char&&); E = pipe]
 FEstream.cpp:104:13: note:   template argument deduction/substitution failed:
 FEstream.cpp: In substitution of 'template<class ... ARGS> decltype (eval<L, R, E>((* this), (forward<ARGS>)(Pipe::operator()::arg)...)) Pipe::operator()(ARGS&& ...) [with ARGS = {ARGS ...}; L = char (*)(); R = void (*)(char&&); E = pipe] [with ARGS = {int}]':
 FEstream.cpp:117:9:   required from here
 FEstream.cpp:104:13: error: no matching function for call to 'eval(Pipe<char (*)(), void (*)(char&&), pipe>&, int)'
 FEstream.cpp:104:13: note: candidates are:
 FEstream.cpp:88:6: note: template<class F, class ... ARGS> decltype (f((forward<ARGS>)(eval::arg)...)) eval(F&, ARGS&& ...)
 FEstream.cpp:88:6: note:   template argument deduction/substitution failed:
 FEstream.cpp:104:13: note:   cannot convert '*(Pipe<char (*)(), void (*)(char&&), pipe>*)this' (type 'Pipe<char (*)(), void (*)(char&&), pipe>') to type 'char (*&)()'
 FEstream.cpp:93:6: note: template<class L, class R, class E, class ... ARGS> decltype (Flow<E>::apply(eval(f.lhs, (forward<ARGS>)(eval::arg)...), f.rhs)) eval(Pipe<L, R, E>&, ARGS&& ...)
 FEstream.cpp:93:6: note:   template argument deduction/substitution failed:
 FEstream.cpp: In substitution of 'template<class L, class R, class E, class ... ARGS> decltype (Flow<E>::apply(eval(f.lhs, (forward<ARGS>)(arg)...), f.rhs)) eval(Pipe<L, R, E>&, ARGS&& ...) [with L = char (*)(); R = void (*)(char&&); E = pipe; ARGS = {int}]':
 FEstream.cpp:104:13:   required by substitution of 'template<class ... ARGS> decltype (eval<L, R, E>((* this), (forward<ARGS>)(Pipe::operator()::arg)...)) Pipe::operator()(ARGS&& ...) [with ARGS = {ARGS ...}; L = char (*)(); R = void (*)(char&&); E = pipe] [with ARGS = {int}]'
 FEstream.cpp:117:9:   required from here
 FEstream.cpp:93:6: error: no matching function for call to 'eval(char (*&)(), int)'
 FEstream.cpp:93:6: note: candidate is:
 FEstream.cpp:88:6: note: template<class F, class ... ARGS> decltype (f((forward<ARGS>)(eval::arg)...)) eval(F&, ARGS&& ...)
 FEstream.cpp:88:6: note:   template argument deduction/substitution failed:
 FEstream.cpp: In substitution of 'template<class F, class ... ARGS> decltype (f((forward<ARGS>)(arg)...)) eval(F&, ARGS&& ...) [with F = char (*)(); ARGS = {int}]':
 FEstream.cpp:93:6:   required by substitution of 'template<class L, class R, class E, class ... ARGS> decltype (Flow<E>::apply(eval(f.lhs, (forward<ARGS>)(eval::arg)...), f.rhs)) eval(Pipe<L, R, E>&, ARGS&& ...) [with L = char (*)(); R = void (*)(char&&); E = pipe; ARGS = {int}]'
 FEstream.cpp:104:13:   required by substitution of 'template<class ... ARGS> decltype (eval<L, R, E>((* this), (forward<ARGS>)(Pipe::operator()::arg)...)) Pipe::operator()(ARGS&& ...) [with ARGS = {ARGS ...}; L = char (*)(); R = void (*)(char&&); E = pipe] [with ARGS = {int}]'
 FEstream.cpp:117:9:   required from here
 FEstream.cpp:88:6: error: too many arguments to function
Process terminated with status 1 (0 minutes, 0 seconds)

发生了什么事情?是我的错误,还是 gcc 不符合 C++11?

//

/

谢谢戴夫S.但是,代码只是简化。事实上,我使用模板Eval::eval:

template<class L,class R,class E>
struct Pipe;
template<class F>
struct Eval {
     template<class...ARGS>
     static auto eval(F&f,ARGS&&... arg)->decltype(f(std::forward<ARGS>(arg)...)) {
          return f(std::forward<ARGS>(arg)...);
     }
};
template<class L,class R,class E>
struct Eval<Pipe<L,R,E> > {
     static auto eval(Pipe<L,R,E>&f)->decltype(Flow<E>::apply(f.lhs,f.rhs)) {
          return Flow<E>::apply(f.lhs,f.rhs);
     }
     template<class...ARGS>
     static void eval(Pipe<L,R,E>&f,ARGS&&...arg) {
          static_assert(!std::is_same<E,pipe>::value,
                        "multiple input for expressionnsample: auto expr=wrap(foo1)<var1|foo2 ;call expr(var2) instead of expr()");
     }
};
template<class L,class R>
struct Eval<Pipe<L,R,pipe> > {
     template<class...ARGS>
     static auto eval(Pipe<L,R,pipe>&f,ARGS&&... arg)->decltype(Flow<pipe>::apply(Eval<L>::eval(f.lhs,std::forward<ARGS>(arg)...),f.rhs)) {
          return Flow<pipe>::apply(Eval<L>::eval(f.lhs,std::forward<ARGS>(arg)...),f.rhs);
     }
};
template<class L,class R,class E>
struct Pipe {
     L lhs;
     R rhs;
     Pipe(L &l,R& r):lhs(l),rhs(r) {
     }
  template<class...ARGS>
   auto operator()(ARGS&&... arg)->decltype(Eval<Pipe>::eval(*this,std::forward<ARGS>(arg)...)) {
        return Eval<Pipe>::eval(*this,std::forward<ARGS>(arg)...);
   }
};

         void streamtest()
        {
            void (*foo1)(char &&)=foo;
            void (*foo2)(int ,int ,short )=foo;
            char (*foo3)()=foo;
            Pipe<char(*)(),void(*)(char&&),pipe> pp(foo3,foo1);
             //pp(); //no call!
        }

错误是:

  • FEstream.cpp:在"struct Eval>"的实例化中:
  • FEstream.cpp:121:9:从"结构管道"中需要
  • FEstream.cpp:134:45:从这里需要
  • FEstream.cpp:110:18:错误:无效使用不完整的类型"结构管道"

  • FEstream.cpp:115:8:错误:声明"结构管道"空 (*)(字符&&),管道>'

  • FEstream.cpp:110:18:错误:未完成类型的使用无效"结构管道"
  • FEstream.cpp:115:8:错误:声明"结构管道"空 (*)(字符&&), 管道>'

进程以状态 1(0 分钟, 0 秒) 6 错误,0 警告

管道::运算符()(ARGS&&...arg) 是一个模板成员函数。为什么我声明变量 Pipe(pp) 会导致错误?它不应该被实例化,因为我没有使用它enter code here


任何人?并且我忘记了Pipe使用评估函数时的状态,例如

template<class...ARGS>
   auto operator()(ARGS&&... arg)->decltype(eval(*this,std::forward<ARGS>(arg)...)) {
        return eval(*this,std::forward<ARGS>(arg)...);
   }

 template<class...ARGS>
   auto operator()(ARGS&&... arg)->decltype(eval<L,R,E>(*this,std::forward<ARGS>(arg)...)) {
        return eval<L,R,E>(*this,std::forward<ARGS>(arg)...);
   }

会像里斯一样出错:模板实例化深度超过最大 900 .....

似乎被选中了 Eval(F&... 而不是 eval(Pipe&f.....未指定模板参数时

由于调用链中的某个位置的参数不匹配,它遇到了问题。 因此,我们可以手动执行此操作以查找问题。

Pipe<char(*)(),void(*)(char&&),pipe> pp(foo3,foo1);使用的是 foo3,它以 0 个参数作为其L,以及 foo1,它以字符值引用作为R。 您的标记结构E pipe

当使用 int 1 调用时。

pp(1)调用eval<L,R,E>(*this, 1),而又调用

Flow<E>::apply(eval(foo3,1),foo1) .

首先,内在的评估被称为。 这试图确定foo3(1)的十进制,然而,foo3被声明为0个参数。 这会导致编译失败,从而导致替换失败。

编辑:随着问题的改变,您的问题是现在您正在为Pipe创建Eval的专用化,但是Eval正在尝试在其返回声明中使用Pipe字段(通过decltype),并且Pipe正在做同样的事情。 你将不得不打破这个循环,以便可以首先定义一些东西,或者至少设置它,以便不引入函数声明中的循环,这样你就可以在完全定义这两种类型后定义方法。

我不确定Eval类试图完成什么。 一种解决方案可能是完全删除它,只需Pipe::operator()更直接地调用该方法。

我正在使用 gcc 4.6 在 Ubuntu 上构建这个(我没有 gcc 4.7 的版本可以尝试),所以 YMMV。

GCC 4.6 : g++-4.6 -std=c++0x test.cpp

  1. void (*foo2)(int ,int ,short )=foo; - 没有与此签名匹配的foo版本,所以我将其注释掉。

  2. error: expected a type, got ‘pipe’ -- pipe似乎在别处定义,因此将其重命名为 pipe_

  3. error: invalid use of ‘this’ at top level -- gcc 4.6 不喜欢auto operator()->decltype(*this)语法,所以用Pipe<L,R,E>(lhs,rhs)替换了*this

  4. error: no match for call to ‘(Pipe<char (*)(), void (*)(char&&), pipe_>) (int)’ - GCC 4.6 未能与operator()匹配。这就是我感到困惑的地方。

叮当 3.1 : clang -std=c++11 test.cpp

  1. 与 GCC 相同的不匹配的 Foo 声明

  2. 与 GCC 相同的"预期'管道'是一种类型"错误

  3. 呼叫operator()error: no matching function for call to object of type 'Pipe<char (*)(), void (*)(char &&), pipe_>'

还行。gcc 和 clang 都表明operator()定义存在问题。

template<class...ARGS>
auto operator()(ARGS&&... arg)->decltype(eval<L,R,E >(*this,std::forward<ARGS>(arg)...));

在这里,您正在使用*this和转发的参数调用evaleval有两个版本:

template<class F,class...ARGS>
auto eval(F& f,ARGS&&... arg)->decltype(f(std::forward<ARGS>(arg)...));

和:

template<class L,class R,class E,class...ARGS>
auto eval(Pipe<L,R,E>&f,ARGS&&... arg)->decltype(Flow<E>::apply(eval(f.lhs,std::forward<ARGS>(arg)...),f.rhs));

现在,由于eval是一个函数,并且所有参数都在其参数中指定,因此无需显式指定它们。这样做就像:

eval<L,R,E >(*this,std::forward<ARGS>(arg)...)

告诉编译器第一个参数是L它不是,它是Pipe<L,R,E>.

operator()定义更改为:

template<class...ARGS>
auto operator()(ARGS&&... arg)->decltype(eval(*this,std::forward<ARGS>(arg)...));

现在崩溃了 Clang 和 GCC!

编辑:好的,现在尝试使用gcc 4.7的新版本,我现在得到:

test.cpp:30:10: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) substituting ‘template<class _Tp> constexpr _Tp&& std::forward(typename std::remove_reference<_Tp>::type&&) [with _Tp = int]’
test.cpp:30:10:   required by substitution of ‘template<class L, class R, class E, class ... ARGS> decltype (Flow<E>::apply(eval(f.lhs, (forward<ARGS>)(arg)...), f.rhs)) eval(Pipe<L, R, E>&, ARGS&& ...) [with L = char (*)(); R = void (*)(char&&); E = pipe_; ARGS = int]’
test.cpp:41:17:   required by substitution of ‘template<class ... ARGS> decltype (eval(Pipe(((Pipe*)this)->Pipe<L, R, E>::lhs, ((Pipe*)this)->Pipe<L, R, E>::rhs), (forward<ARGS>)(Pipe::operator()::arg)...)) Pipe::operator()(ARGS&& ...) [with ARGS = {ARGS ...}; L = char (*)(); R = void (*)(char&&); E = pipe_] [with ARGS = {int}]’
test.cpp:25:10:   required by substitution of ‘template<class F, class ... ARGS> decltype (f((forward<ARGS>)(eval::arg)...)) eval(F&, ARGS&& ...) [with F = Pipe<char (*)(), void (*)(char&&), pipe_>; ARGS = {int}]’

在41:17(Pipe<L,R,E>::operator())和25:10(eval<F,ARGS>())之间递归,所以它没有拾取evalPipe专业化。现在我又被困住了。