禁用默认模板,仅通过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?),这样重载解决方案只考虑显式专业化,如果找不到匹配,则会生成编译时错误。这能做到吗?

clang和msvc之间的可移植解决方案是必须的,但我使用的是两者的最新版本。

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

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

如果进行

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

它按预期工作:实例

虽然Jarod的答案解决了其中一个问题,但我仍然需要一种方法来重载函数参数(在这种情况下会产生"无匹配模板"错误)-我可能没有在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

当然,额外的好处是编译器在调用/实例化时用正确的错误消息识别错误,而不是一些随机的静态断言/链接器错误。成功

最新更新