草庐IT

c++ - Visual C++ 无法推断在 ctor 中用作默认值的函数的给定(!)模板参数

coder 2024-02-22 原文

我正在尝试使用模板函数返回模板类构造函数中参数的默认值。函数的模板参数也是类的模板参数。我在下面提供了一个示例。

背景 该示例显示了确切的用例和依赖项,因为它们也出现在我的应用程序中。 X 类实际上是一个相当大的类,它管理一个大数据 block ,该大数据 block 被分成更小的 block 。类助手是一个内存管理器,它以较小的 block 大小分配和释放内存。实际上,GetHelper 函数会在运行时尝试推导出 Helper 的一些构造函数参数,所以这就是我使用这种设计的原因。

实际问题 当定义了宏 USE_NS 和 SHOW_ERROR 时,代码无法编译,在第 66 行给出错误 C2783 无法推断模板参数。这是我尝试使用模板函数初始化构造函数参数的地方GetHelper(提供模板参数!)。请记住,GetHelper 来自与类 X 不同的 namespace 。还请注意,在第 72 行中使用了相同的函数调用来初始化构造函数体内的 Helper 对象。怎么了?有解决方案或解决方法吗?

我正在使用 Visual Studio 2008 Pro 和 boost 1.47。

#include <iostream>
#include <boost/shared_ptr.hpp>

// 1 means macro is defined
// USE_NS 1 and SHOW_ERROR 1 -> Compileerror
// USE_NS 0 and SHOW_ERROR 1 -> Works, Output: 8 and 16.5
// USE_NS 1 and SHOW_ERROR 0 -> Works, Output: 3
// USE_NS 0 and SHOW_ERROR 0 -> Works, Output: 3


#define USE_NS
#define SHOW_ERROR


#ifndef USE_NS
#define NH 
#define NX
#endif

#ifdef USE_NS
namespace NH
{
#endif

template< typename TNumAtH, size_t TSizeAtH>
class Helper
{
public:
    TNumAtH* x;

    Helper()
    {
        x = new TNumAtH[TSizeAtH];
        x[0] = static_cast< TNumAtH >( 8 );
    }

    ~Helper()
    {
        delete [] x;
    }
};

template <typename TNumAtF, size_t TSizeAtF >
boost::shared_ptr< Helper< TNumAtF, TSizeAtF > > GetHelper()
{
    return boost::shared_ptr< Helper< TNumAtF,TSizeAtF > > ( new Helper< TNumAtF, TSizeAtF >() );
}

#ifdef USE_NS
}

namespace NX
{
#endif

template< typename TNumAtX, size_t TSize >
class X
{
public:
    boost::shared_ptr< NH::Helper< TNumAtX, TSize > > a;

#ifdef SHOW_ERROR
    //this produces an error if namespace are used, if no namespaces are used
    //NH is reduced to a blank (see macros at line 17 and 18
    X( boost::shared_ptr< NH::Helper< TNumAtX, TSize > > h = NH::GetHelper< TNumAtX, TSize >() );
#endif

    X( TNumAtX firstElem )
    {
        //this works with namespaces and without namespaces
        a = NH::GetHelper< TNumAtX, TSize >();
        a->x[0] = firstElem;
    }

    TNumAtX GetNum()
    {
        return a->x[0];
    }

};

#ifdef SHOW_ERROR
template< typename TNumAtX, size_t TSize >
X<TNumAtX, TSize>::
X( boost::shared_ptr< NH::Helper< TNumAtX, TSize > > h ) : a( h )
{
}
#endif

#ifdef USE_NS
}
#endif


int main( int argc, char** argv )
{
    std::cout << "Hello at TestTemplateFunction" << std::endl;
    //use case one
#ifdef SHOW_ERROR
    NX::X<int, 5> x1;
#else
    NX::X<int, 5> x1( 3 );
#endif
    std::cout << "Use case 1: " << x1.GetNum() << std::endl;

    //use case two
#ifdef SHOW_ERROR
    typedef float T;
    size_t const N = 9;
    boost::shared_ptr< NH::Helper<T, N> > h( new NH::Helper<T, N> );
    h->x[0] = 16.5f;
    NX::X<T, N> x2( h );
    std::cout << "Use case 2: " << x2.GetNum() << std::endl;
#endif

    std::cout << "Hit the any key" << std::endl;
    getchar();
    return 0;  
}

这是 CMakeLists.txt 文件

PROJECT(TestTemplateFunction)
CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )

FIND_PACKAGE( BOOST )

INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} )

ADD_EXECUTABLE( TestTemplateFunction main.cpp  )

编辑:编译错误

main.cpp(65) : error C2783: 'boost::shared_ptr<NH::Helper<TNumAtH,TSizeAtH>>    NH::GetHelper(void)' : could not deduce template argument for 'TNumAtF'
main.cpp(44) : see declaration of 'NH::GetHelper'
main.cpp(65) : error C2783: 'boost::shared_ptr<NH::Helper<TNumAtH,TSizeAtH>>       NH::GetHelper(void)' : could not deduce template argument for 'TSizeAtF'
main.cpp(44) : see declaration of 'NH::GetHelper'

最佳答案

突发新闻

在 Clang 3.2 上报告该问题后,看来这实际上是一个 C++ 缺陷。你看到 bug discussion in the clang database .

引用理查德·史密斯的话:

This is a defect in C++ itself:

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#325

Clang matches the behavior of all other C++ compilers here; this is not a bug (though depending on the way in which that issue is resolved, we may need to revisit this).

The workaround is to add parentheses around the default argument expression.

问题是歧义之一。例如,通过查看:

int = a < b, c < d > ( e )

...是一个参数,并且...

int = a < b, c < d > ( e ) = 0

我们可以体会到模板参数之间不容易区分,正则<调用以及因此构成默认参数的内容。

如果我们遵循 Richard 的建议并添加括号,那么我们将不再受制于编译器的突发奇想。或者至少,I can guarantee Clang gets it right (修订版 6):

 X( boost::shared_ptr< NH::Helper<T, N> > h = (NH::GetHelper<T, N>()) );

在我看来这像是一个编译器错误。

我测试了您的代码(感谢您顺便发布了一个完整的示例)on liveworkspace gcc 4.7.2 产生以下输出:

Hello at TestTemplateFunction
Use case 1: 8
Use case 2: 16.5

当 clang 3.2 产生时:

Compilation finished with errors:
source.cpp:65:86: error: unknown type name 'TSize'
X( boost::shared_ptr< NH::Helper< TNumAtX, TSize > > h = NH::GetHelper< TNumAtX, TSize >() );
                                                                                 ^
source.cpp:65:92: error: expected ')'
X( boost::shared_ptr< NH::Helper< TNumAtX, TSize > > h = NH::GetHelper< TNumAtX, TSize >() );
                                                                                       ^
source.cpp:65:6: note: to match this '('
X( boost::shared_ptr< NH::Helper< TNumAtX, TSize > > h = NH::GetHelper< TNumAtX, TSize >() );
 ^
source.cpp:65:84: error: expected '>'
X( boost::shared_ptr< NH::Helper< TNumAtX, TSize > > h = NH::GetHelper< TNumAtX, TSize >() );
                                                                               ^
source.cpp:85:1: error: out-of-line definition of 'X<TNumAtX, TSize>' does not match any declaration in 'X<TNumAtX, TSize>'
X( boost::shared_ptr< NH::Helper< TNumAtX, TSize > > h ) : a( h )
^
4 errors generated.

我以两种方式稍微修改了示例(更改 5):

  • 介绍static boost::shared_ptr<Helper> Get() { return boost::shared_ptr<Helper>(new Helper()); }内嵌在 Helper 中模板

  • 做了一个typedef NH::Helper< TNumAtX, TSize > HelperX并将其用于构造函数 X(boost::shared_ptr<Helper> h = Helper::Get());

现在 clang 设法编译了代码。

我设法将(clang 的)错误减少到:

template <typename T, unsigned N>
struct Helper {};

template <typename T, unsigned N >
Helper< T, N > GetHelper() { return Helper< T, N > (); }

template < typename T, unsigned N >
struct X {
    X( Helper< T, N > h = GetHelper<T, N>() ) {}
};

你可以see it here .

关于c++ - Visual C++ 无法推断在 ctor 中用作默认值的函数的给定(!)模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14401308/

有关c++ - Visual C++ 无法推断在 ctor 中用作默认值的函数的给定(!)模板参数的更多相关文章

  1. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  2. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  3. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  4. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  5. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  6. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  7. ruby-on-rails - 无法在centos上安装therubyracer(V8和GCC出错) - 2

    我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e

  8. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  9. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  10. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

随机推荐