2017-10-21 536 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有一些允許模式,它允許從右值構造一個非常量左值引用,這可能是爲什麼它起作用。