2014-10-06 56 views
2

考虑以下系统:禁用默认模板,并且只使用专门通过SFINAE

template<typename T> 
    struct wrapper 
    { 
     operator T *() { return nullptr; } 
    }; 

template<typename Ret, typename T> 
    Ret func(T); 

template<> 
    int func(float * in) 
    { 
     std::cout << "long"; 
    } 

template<> 
    long func(float * in) 
    { 
     std::cout << "int"; 
    } 

包装的目的是允许它衰减到它的模板的类型(它是围绕一个缓冲包装类型)。此外,我有一套功能模板的模板专业化。这是为了避免仅基于返回类型重载时的常见错误。

这不工作,虽然,如前所述这里:相反

// the following should work, but doesn't because it's instantiating 
// the func<ret, wrapper<float>> which doesn't exist resulting in a linker error 
// instead of selecting the int func(float *) overload 
wrapper<float> w; 
func<int>(w); 

,我想这生成编译时错误(但同样,它生成一个链接时错误):

// the following should generate a compile-time error 
// since no explicit overload for int func(int *) exists 
wrapper<int> w2; 
func<int>(w2); 

所以理想情况下,我想禁用原始模板(如果可能的话可以通过sfinae?),这样重载决议只考虑明确的特化,并且如果没有找到匹配就会产生编译时错误。这可以做到吗?

铿锵和msvc之间的便携式解决方案是必须的,但我使用两者的最新版本。

+1

您的问题,还不如说是模板参数推导,不考虑隐式转换尽可能多的重载决议。 – 2014-10-06 16:04:02

+0

@ P0W因为你不能超载这两个。唯一的区别是返回类型。 – 2014-10-06 16:14:17

+0

@TC Ahh我看到了,谢谢 – P0W 2014-10-06 16:15:25

回答

1

如果你

template<typename Ret> Ret func(float*); 

它按预期工作:Live example

+0

感谢您的想法 - 这是解决方案的一部分(请参阅我的回答) – Shaggi 2014-10-06 18:45:00

1

虽然贾罗德的回答解决的问题之一,我仍然需要一种方法来重载函数的参数(在这种情况下,会产生'没有匹配模板'的错误) - 我可能没有在OP中说明。

在我看来,参数类型总是依赖于返回类型。然后,我可以建立一个辅助性结构,即会做SFINAE:

template<typename T> 
    struct option_of; 

template<> 
    struct option_of<int> 
    { 
     typedef float value; 
    }; 

template<> 
    struct option_of<long> 
    { 
     typedef double value; 
    }; 

,然后默认的模板应该是这样的:

template<typename Ret> 
    Ret func(typename const option_of<Ret>::value *); 

,然后重载可以构建这样的:

template<> 
    int func(const float * in) 
    { 
     std::cout << "long"; 
    } 

template<> 
    long func(const double * in) 
    { 
     std::cout << "int"; 
    } 

- 没有问题。请注意,任何其他组合的返回和参数类型都是无效的(因为它们不是原始模板的专门化,只考虑我给出的选项)。这也降低了仅过载分辨率的两个过载,并因此使这成为可能:

wrapper<float> w; 
func<int>(w); // works 
func<long>(w); // invalid, because no combination of long and float exists according to option_of 

wrapper<int> w2; // works, but 
func<int>(w2); // invalid because option_of doesn't consider int's 

课程的额外的好处是编译器可以识别在呼叫/实例化与正确的错误消息的错误,而不是一些随机static_assert /链接器错误。成功!

+0

在您的示例中,参数不仅取决于返回类型,还有其他解决方法。如果您创建了return_of :: value,那么您的模板参数可以是隐式的,您可以在不使用模板参数的情况下调用func(w2)。 – sluki 2015-07-03 10:43:18

1

另一种方法可以是使用static_assert:

template<typename Ret, typename T> 
Ret func(T) { 
    static_assert(false, "template specialization required"); 
}