为什么不允许使用0作为void *的默认非类型模板参数

时间:2016-07-01 22:49:29

标签: c++ templates c++11 c++14 void

为什么以下代码无法编译?尽管void* ptr = 0;

是合法的
template <void* ptr = 0>
void func();

int main() {
    func();
    return 0;
}

我问,因为我发现一个非常受信任的来源做了类似的事情而且无法在我的机器上编译

注意应该在我的问题上发布编译错误,所以这里是

so_test.cpp:1:23: error: null non-type template argument must be cast to template parameter type 'void *'
template <void* ptr = 0>
                      ^
                      static_cast<void *>( )
so_test.cpp:1:17: note: template parameter is declared here
template <void* ptr = 0>
                ^
so_test.cpp:5:5: error: no matching function for call to 'func'
    func();
    ^~~~
so_test.cpp:2:6: note: candidate template ignored: substitution failure [with ptr = nullptr]: null non-type template argument must be cast to template parameter type 'void *'
void func();
     ^

2 个答案:

答案 0 :(得分:9)

不允许使用 if (output == null) throw new ArgumentNullException("output"); string args; ProcessStartInfo psi = new ProcessStartInfo(); psi.FileName = FindMediaPlayerPath("mplayer.exe"); //psi.FileName = @"x:\mplayer.exe"; psi.UseShellExecute = false; psi.RedirectStandardInput = true; psi.RedirectStandardError = true; psi.RedirectStandardOutput = true; psi.CreateNoWindow = true; psi.WorkingDirectory = Path.GetDirectoryName(DestinationFileName); psi.Verb = "runas"; args = "-wid "; args += Variables.MediaPlayerHandle; args += " -ao pcm:fast:file="; args += Path.GetFileName(DestinationFileName); if (NeedToCut == true) { args += " -ss " + Start + " -endpos " + End; } //args += " -vo null -vc null -quiet "; //-wid will tell MPlayer to show output inisde our panel args += " " + SourceFileName; psi.Arguments = args; 类型的模板参数。参见标准中的[temp.param] / 4,也总结在http://en.cppreference.com/w/cpp/language/template_parameters#Non-type_template_parameter

  

非类型模板参数应具有以下之一(可选 cv-qualified )类型:

     
      
  • 整数或枚举类型,
  •   
  • 指向对象或指向函数的指针,
  •   
  • 对对象的左值引用或对函数的左值引用,
  •   
  • 指向成员的指针,
  •   
  • void*
  •   

由于std::nullptr_t不是对象或函数类型,void不属于允许的类型。

附录:编译时已知的void*值不是很有用。由于在常量表达式中不允许void*,因此无法在编译时检查其值;也不可能在编译时将其转换为reinterpret_cast某些对象类型T*

答案 1 :(得分:1)

您尝试使用int初始化指针。许多隐式转换(包括整数到指针转换)不会发生在非类型模板参数中。

C ++ 14中对于指向对象类型的指针的非模板参数的行为的cppreference summary是:

  

对于指向对象的指针,模板参数必须指定具有静态存储持续时间和链接(内部或外部)的对象的地址,或者计算为适当的空指针或std :: nullptr_t值的常量表达式

所以代码可以是:

template <void* ptr = nullptr>
void f();

脚注:似乎不清楚是否允许void *作为参数类型,但编译器接受上述代码。