2017-10-21 46 views
2

我目前正在探索C++ 17的补充。在playing around withstd::variant之后,也想用std::optional,同样的例子。目前看到的是,编译失败,因为以下错误:C++ 17:lambda转std ::函数转换失败

error: no viable conversion from returned value of type 
     '(lambda at ./html_parser.hpp:53:9)' to function return type 'Parser<char>' (aka 
     'std::__1::function<std::__1::optional<std::__1::pair<char, std::__1::basic_string<char> > > 
     (std::__1::basic_string<char>)>') 
     return [=](std::string& input) -> ParserResult<char> { 
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
/home/acid/tools/include/c++/v1/functional:1627:5: note: candidate constructor not viable: no known conversion 
     from '(lambda at ./html_parser.hpp:53:9)' to 'std::nullptr_t' (aka 'nullptr_t') for 1st argument 
    function(nullptr_t) _NOEXCEPT : __f_(0) {} 
    ^
/home/acid/tools/include/c++/v1/functional:1628:5: note: candidate constructor not viable: no known conversion 
     from '(lambda at ./html_parser.hpp:53:9)' to 'const 
     std::__1::function<std::__1::optional<std::__1::pair<char, std::__1::basic_string<char> > > 
     (std::__1::basic_string<char>)> &' for 1st argument 
    function(const function&); 
    ^
/home/acid/tools/include/c++/v1/functional:1629:5: note: candidate constructor not viable: no known conversion 
     from '(lambda at ./html_parser.hpp:53:9)' to 'std::__1::function<std::__1::optional<std::__1::pair<char, 
     std::__1::basic_string<char> > > (std::__1::basic_string<char>)> &&' for 1st argument 
    function(function&&) _NOEXCEPT; 
    ^
/home/acid/tools/include/c++/v1/functional:1631:5: note: candidate template ignored: requirement 
     '__callable<(lambda at ./html_parser.hpp:53:9)>::value' was not satisfied [with _Fp = 
     (lambda at ./html_parser.hpp:53:9)] 
    function(_Fp); 
    ^
1 error generated. 

为了解析HTML给予DOM,开始与一些声明解析器组合如下:

#pragma once 

#include <string> 
#include <utility> 
#include <functional> 
#include <optional> 

namespace dragon { 
    namespace html { 
     namespace parser { 
      template <typename ParserOutput, typename ParserInput = std::string> 
      using ParserResult = std::optional<std::pair<ParserOutput, ParserInput>>; 

      template<typename ParserOutput, typename ParserInput = std::string> 
      using Parser = std::function<ParserResult<ParserOutput, ParserInput>(ParserInput)>; 

      template <typename ParserOutput, typename ParserInput = std::string> 
      auto parse(Parser<ParserOutput, ParserInput> p, ParserInput i) -> ParserResult<ParserOutput, ParserInput>{ 
       return p(i); 
      } 

      // few parser combinators. 

      // thenP combinator: applies the first parser, if it succeeds apply the second to the rest of 
      // the input left over by the first parser. 
      // currently just fails and returns empty!! does not provide any debugging info/msg 
      // as to why the parsing failed. 
      template<typename FirstParser, typename SecondParser> 
      auto thenP(FirstParser f, SecondParser s) { 
       return [=](std::string input) -> decltype(parse(s, std::string())) { 
        auto fv = parse(f, input); 

        if (fv) { 
         auto fvv = *fv; 
         return parse(s, fvv.second); 
        } 
        else { 
         return {}; 
        } 
       }; 
      } 

      template<typename FirstParser, typename SecondParser> 
      auto choiceP(FirstParser f, SecondParser s) { 
       return [=](std::string input) { 
        auto fv = parse(f, input); 
        if (!fv) return parse(s, input); 
        return fv; 
       }; 
      } 

      auto charP(char match) -> Parser<char> { 
       return [=](std::string& input) -> ParserResult<char> { 
        if ((input.empty() == false) && (input[0] == match)) { 
         return std::make_pair(input[0], input.substr(1)); 
        } 
        return {}; 
       }; 
      } 
     } 
    } 
} 

我看到上面的错误,当试图编译如下所示的简单使用:

int main() 
{ 
    auto less = Parser::parser::charP('<'); 
    auto greater = Parser::parser::charP('>'); 

    auto lag = Parser::parser::thenP(less, greater); 
    auto log = Parser::parser::choiceP(less, greater); 

    auto lagv = lag("<>"); 
    auto logv = log("|>"); 

    return 0; 
} 

这个编译罚款与Visual Studio 2017(std = C++ - latest)。但Clang给出了上述错误。试图找出这两个编译器之间的差异。以及如何用Clang解决这个问题。

+3

将来,请尝试将您的问题缩减为[mcve]。这里有很多不相关的代码,这使得很难看出问题是什么。 – Barry

回答

5

这是非法的构造:

auto charP(char match) -> Parser<char> { 
    return [=](std::string& input) -> ParserResult<char> { ... }; 
} 

出于同样的原因,这是非法的构造:

std::function<void(int)> f = [](int&){}; 

右边的拉姆达是可调用与int,只一个int&,所以你不能从它构造一个function<void(int)>。 MSVC有一些允许模式,它允许从右值构造一个非常量左值引用,这可能是为什么它起作用。