如何在编译时决定'auto'返回类型?

时间:2017-11-23 10:06:27

标签: c++ visual-c++ lambda c++17

在我的天真中,我认为这会编译。唉不行。我正在使用Visual Studio 2017社区完全更新。

 namespace basic_problem {  
   auto msvc_does_not_compile = [] ( auto _string ) 
    -> std::vector< decltype(_string) >
  {
    return std::vector<decltype(_string)>{};
  };
}

编译尝试:

int main(int argc, char* argv[])
{
  auto vec = basic_problem::msvc_does_not_compile(std::string{});
  return 0 ;
}

制作:

error C2514: 'std::vector<unknown-type,std::allocator<_Ty>>': class has no constructors
1>        with
1>        [
1>            _Ty=unknown-type
1>        ]
1>        program.cpp(97): note: see declaration of 'std::vector<unknown-
           type,std::allocator<_Ty>>'
1>        with
1>        [
1>            _Ty=unknown-type
1>        ]

我知道我在这里(也许)已经到了界限。任何想法的人?这在C ++ 17中是否可行?基本上我想在运行时决定返回什么类型。不使用(明显)模板。只是'汽车'和lambdas。

当然C ++不会让我这样做。但即使I use if constexpr msvc拒绝接球:

    auto msvc_does_not_compile_too = [](auto _string )
{
    using string_type = decltype(_string);

    if constexpr ( std::is_same<string_type, std::string>::value )
          return std::vector<std::string> ;
    else {
        return std::vector<std::wstring>;
    }
};

奇怪的是我无法在编译时决定在运行时需要什么类型。使用lambda和auto,即。

谢谢...

2 个答案:

答案 0 :(得分:2)

在godbolt.org的编译器浏览器中,我发现MSVC 2017 RTW 19.10.25017 complains about the simplest use of constexpr if即使有标记/std:c++latest。但是,an official blog post声称自VS 2017.3 [P2](非RTW)以来对constexpr if的支持。您应该检查您的MSVC版本是否使用编译标记constexpr if处理/std:c++latest的简单用法。

如果使用简单的函数模板(如果需要,可以使用特殊化),使用简单的重载,你想要实现的目标就可以正常工作

https://godbolt.org/g/BwuSPG

#include <string>
#include <vector>

namespace basic_problem {
    auto now_it_works(const std::string&) {
      return std::vector<std::string>{};
    }

    auto now_it_works(const std::wstring&) {
      return std::vector<std::wstring>{};
    }
}

int main(int argc, char* argv[]) {
  auto str = basic_problem::now_it_works(std::string{});
  static_assert(std::is_same<
    decltype(str), std::vector<std::string>
  >{}, "");

  auto wstr = basic_problem::now_it_works(std::wstring{});
  static_assert(std::is_same<
    decltype(wstr), std::vector<std::wstring>
  >{}, "");

  return 0;
}

作为旁注,工作代码说明您的标题具有误导性:决定返回哪种类型不能在运行时进行。相反,在编译时选择适当的模板实例化(或特化)重载。

答案 1 :(得分:0)

要求:获取表示命令行的向量。对于在WIN 10中可能具有命令行的所有类型的可执行文件执行此操作。

但我不是在这里让人们做我的&#34;家庭作业&#34;我在这里检查我是否正确使用C ++ 17 lambda + auto解决方案。它似乎简单健壮,快速。结果证明它不是使用msvc。

实际用例在MSVC + WIN情况下对全局变量进行操作

     #include <stdlib.h>
     #define _CRT_DECLARE_GLOBAL_VARIABLES_DIRECTLY
       auto   wargv_ = (__wargv);
       auto    argv_  = (__argv );
       auto    argc_  = (__argc ); 
   #undef _CRT_DECLARE_GLOBAL_VARIABLES_DIRECTLY

到目前为止一切顺利。但是我们如何判断wargv_何时为null以及何时argv_为null?似乎wargv_总是为空,但是人们无法确定。

那么我们如何封装解决方案的核心?有一个lambda。实施几乎是微不足道的。没有重载,也没有模板。只是现代的C ++。

    auto command_line_data = [&]() {
      if ( wargv_ != nullptr ) {
        return std::vector<std::wstring>(wargv_, wargv_ + argc_);
      }
       else {
        return std::vector<std::string>(argv_, argv_ + argc_);
      }
};

唉msvc无法接受这个......感谢@Julius对gcc,clang,msvc进行编码的比较。

更新 - &#34;简单&#34;和msvc友好解决方案

 #include <stdlib.h>
namespace {
#define _CRT_DECLARE_GLOBAL_VARIABLES_DIRECTLY

const auto  wargv_ = (__wargv);
const auto  argv_ = (__argv);
const auto  argc_ = (__argc);

#undef _CRT_DECLARE_GLOBAL_VARIABLES_DIRECTLY

namespace {

    using wvecT = std::vector<std::wstring>;
    using nvecT = std::vector<std::string >;

    // wargv_ !=  nullptr
    inline auto decide(std::true_type tt) {
        return wvecT{ wargv_, wargv_ + argc_ };
    }
    // wargv_ ==  nullptr
    inline auto decide( bool ft) {
        return nvecT{ argv_, argv_ + argc_ };
    }
}

auto cli_data = []() {
    return decide( 
        wargv_ != NULL 
        ? std::true_type{}
        : false
    );
};
} // nspace

我现在没有时间进行比较,但是决定()重载和调用似乎&#34;搞笑&#34;,我想感谢msvc运行时......

我确信这可以进行优化并使其看起来不像特技。但这有效..

VS 15.5更新后(对我来说:2017-12-05)

直到昨天(2017-12-06),这还没有在MSVC下进行编译。但是在VS 15.5更新之后就可以了。

    auto msvc_does_compile = [](auto _string)
     {
      using string_type = decltype(_string);
      return std::vector<string_type>{};
     };
   /*
    OK since VS 2017 15.5 update
   auto vec1 = msvc_does_compile( std::string{} );
   */

添加显式返回类型仍会像往常一样阻塞MSVC,而不是gcc / clang:

auto msvc_does_not_compile = [](auto _string)
    // explicit return type makes msvc not to compile
    -> std::vector< decltype(_string) >
  {
    using string_type = decltype(_string);
    return std::vector<string_type>{};
  };

即使在IDE编辑器阶段,也会停止一些相同但更简单的事情:

    auto msvc_ide_does_not_allow = []( bool wide )
    {
       if (wide)
        return std::vector<std::string>();

        return std::vector<std::wstring>();
    };

是的,再次说麻烦的gcc / clang对上面的任何一个都没有问题。尝试哪种在线格式你更愿意说服自己...

编辑01FEB2018

我的解决方案是错误的,这是一个特技。这是我们现在可以做的最好的事情:

#pragma once

#include <cstdlib>
#include <vector>
#include <string>

#include <tchar.h>

namespace stwish {

    using vector_tstring_type = std::vector<std::basic_string<_TCHAR> >;
    namespace {

        auto cli_data = []() {
            try {
                return
                    vector_tstring_type
                {
                    __targv,
                    (__targv ?
                    __targv + __argc :
                    __targv)
                };
            }
            catch (...) {
                throw std::runtime_error(__FUNCSIG__ " failed..." );
            }
        };
    }
}

这是Steve Wishnousky先生(微软)设计的解决方案。谢谢史蒂夫。

相关问题