防止隐式模板实例化

时间:2017-01-13 12:20:23

标签: c++ templates overloading overload-resolution

在像这样的方法过载情况中:

struct A
{
  void foo( int i ) { /*...*/ }
  template<typename T> void foo( T t ) { /*...*/ }
}

除非明确命令,否则如何阻止模板实例化?:

A a;
a.foo<int>( 1 ); // ok
a.foo<double>( 1.0 ); // ok
a.foo( 1 ); // calls non-templated method
a.foo( 1.0 ); // error

谢谢!

4 个答案:

答案 0 :(得分:9)

您可以引入一个阻止template argument deductiondepedent_type结构。

template <typename T>
struct dependent_type
{
    using type = T;
};

struct A
{
  void foo( int i ) { /*...*/ };
  template<typename T> void foo( typename dependent_type<T>::type t ) { /*...*/ }
}

在您的示例中:

a.foo<int>( 1 );      // calls the template
a.foo<double>( 1.0 ); // calls the template
a.foo( 1 );           // calls non-templated method
a.foo( 1.0 );         // calls non-templated method (implicit conversion)

wandbox example

cppreference > template argument deduction > non-deduced contexts解释了此行为。)

如果您想使a.foo( 1.0 )出现编译错误,您需要约束第一个重载:

template <typename T> 
auto foo( T ) -> std::enable_if_t<std::is_same<T, int>{}> { }

此技术使foo的上述重载仅采用int个参数:不允许隐式转换(例如floatint 。如果这不是您想要的,请考虑TemplateRex的答案。

wandbox example

(使用上述约束函数,调用a.foo<int>( 1 )时两个重载之间存在奇怪的交互。我asked a question about it因为我不确定基本规则是什么指导它。)

答案 1 :(得分:1)

到目前为止,最简单的方法是明确删除您不想要的超载:

void foo(double) = delete;

即。有以下明确的例子:

#include <iostream>

struct A
{
    void foo(int) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
    void foo(double) = delete;

    template<typename T> 
    void foo( T ) {std::cout << __PRETTY_FUNCTION__ << "\n"; }
};

int main() 
{    
    A a;
    a.foo<int>( 1 );        // ok
    a.foo<double>( 1.0 );   // ok
    a.foo( 1 );             // calls non-templated method
    a.foo( 1.0 );           // error    
}

主要注释掉this prints

中的最后一行
void A::foo(T) [with T = int]
void A::foo(T) [with T = double]
void A::foo(int)

并在this prints

中留下最后一行
prog.cc: In function 'int main()':
prog.cc:18:16: error: use of deleted function 'void A::foo(double)'
     a.foo( 1.0 );           // error
                ^
prog.cc:6:10: note: declared here
     void foo(double) = delete;

答案 2 :(得分:0)

在底池中添加另一个建议,并且与Vittorio的答案类似,您还可以在签名中添加另一个模板参数:

template <class UserType, class InputType>
void foo(InputType x){...}

然后要使用它,您必须指定第一个模板参数,因为它无法推断。这有一点点优势,能够区分用户想要的内容和传入的内容,在某些情况下可能会有用。

答案 3 :(得分:0)

Halelulah !!!!!!!经过多年的悲伤,我终于找到了答案。因为我知道cpp规则,与定义分开的声明不只是被扔到转储中!!!

// declare template
template <class T> void test();

// declare specialization
template <> // very import to start with this token
void<int> test();

// implicit instantiation
template // if you use this instead, you get instantiation
void<int> test();

我仍然想知道为什么这是必要的。可能是来自Cpp委员会的明智人员的优化。