为什么函数模板不能部分特化?

发布于 2024-10-19 00:14:13 字数 409 浏览 1 评论 0 原文

我知道语言规范禁止函数模板的部分专业化。

我想知道为什么禁止这样做?它们没有用吗?

template<typename T, typename U> void f() {}   //allowed!
template<> void f<int, char>()            {}   //allowed!
template<typename T> void f<char, T>()    {}   //not allowed!
template<typename T> void f<T, int>()     {}   //not allowed!

I know the language specification forbids partial specialization of function template.

I would like to know the rationale why it forbids it? Are they not useful?

template<typename T, typename U> void f() {}   //allowed!
template<> void f<int, char>()            {}   //allowed!
template<typename T> void f<char, T>()    {}   //not allowed!
template<typename T> void f<T, int>()     {}   //not allowed!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

拒绝两难 2024-10-26 00:14:13

AFAIK 这在 C++0x 中发生了变化。

我猜这只是一个疏忽(考虑到您总是可以通过更详细的代码获得部分专业化效果,通过将函数放置为 static< /code> 类的成员)。

如果有的话,您可以查找相关的 DR(缺陷报告)。

编辑:检查这一点,我发现其他人也相信这一点,但没有人能够在标准草案中找到任何此类支持。 这个SO线程似乎表明不支持函数模板的部分专业化在 C++0x 中。

编辑2:只是我所说的“将函数作为类的静态成员”的含义的一个示例:

#include <iostream>
using namespace std;

// template<typename T, typename U> void f() {}   //allowed!
// template<> void f<int, char>()            {}   //allowed!
// template<typename T> void f<char, T>()    {}   //not allowed!
// template<typename T> void f<T, int>()     {}   //not allowed!

void say( char const s[] ) { std::cout << s << std::endl; }

namespace detail {
    template< class T, class U >
    struct F {
        static void impl() { say( "1. primary template" ); }
    };

    template<>
    struct F<int, char> {
        static void impl() { say( "2. <int, char> explicit specialization" ); }
    };

    template< class T >
    struct F< char, T > {
        static void impl() { say( "3. <char, T> partial specialization" ); }
    };

    template< class T >
    struct F< T, int > {
        static void impl() { say( "4. <T, int> partial specialization" ); }
    };
}  // namespace detail

template< class T, class U >
void f() { detail::F<T, U>::impl(); }    

int main() {
    f<char const*, double>();       // 1
    f<int, char>();                 // 2
    f<char, double>();              // 3
    f<double, int>();               // 4
}

AFAIK that's changed in C++0x.

I guess it was just an oversight (considering that you can always get the partial specialization effect with more verbose code, by placing the function as a static member of a class).

You might look up the relevant DR (Defect Report), if there is one.

EDIT: checking this, I find that others have also believed that, but no-one is able to find any such support in the draft standard. This SO thread seems to indicate that partial specialization of function templates is not supported in C++0x.

EDIT 2: just an example of what I meant by "placing the function as a static member of a class":

#include <iostream>
using namespace std;

// template<typename T, typename U> void f() {}   //allowed!
// template<> void f<int, char>()            {}   //allowed!
// template<typename T> void f<char, T>()    {}   //not allowed!
// template<typename T> void f<T, int>()     {}   //not allowed!

void say( char const s[] ) { std::cout << s << std::endl; }

namespace detail {
    template< class T, class U >
    struct F {
        static void impl() { say( "1. primary template" ); }
    };

    template<>
    struct F<int, char> {
        static void impl() { say( "2. <int, char> explicit specialization" ); }
    };

    template< class T >
    struct F< char, T > {
        static void impl() { say( "3. <char, T> partial specialization" ); }
    };

    template< class T >
    struct F< T, int > {
        static void impl() { say( "4. <T, int> partial specialization" ); }
    };
}  // namespace detail

template< class T, class U >
void f() { detail::F<T, U>::impl(); }    

int main() {
    f<char const*, double>();       // 1
    f<int, char>();                 // 2
    f<char, double>();              // 3
    f<double, int>();               // 4
}
桃扇骨 2024-10-26 00:14:13

好吧,你确实不能进行部分函数/方法特化,但你可以进行重载。

template <typename T, typename U>
T fun(U pObj){...}

// acts like partial specialization <T, int> AFAIK 
// (based on Modern C++ Design by Alexandrescu)
template <typename T>
T fun(int pObj){...} 

确实是这样,但不知道你是否满意。

Well, you really can't do partial function/method specialization however you can do overloading.

template <typename T, typename U>
T fun(U pObj){...}

// acts like partial specialization <T, int> AFAIK 
// (based on Modern C++ Design by Alexandrescu)
template <typename T>
T fun(int pObj){...} 

It is the way but I do not know if it satisfy you.

旧人哭 2024-10-26 00:14:13

一般来说,由于重载的问题,根本不建议专门化函数模板。这是来自 C/C++ 用户期刊的一篇好文章: http://www.gotw.ca/publications /mill17.htm

它包含对您问题的诚实回答:

一方面,你不能部分地特化它们——这很大程度上只是因为语言说你不能。

In general, it's not recommended to specialize function templates at all, because of troubles with overloading. Here's a good article from the C/C++ Users Journal: http://www.gotw.ca/publications/mill17.htm

And it contains an honest answer to your question:

For one thing, you can't partially specialize them -- pretty much just because the language says you can't.

瞳孔里扚悲伤 2024-10-26 00:14:13

由于您可以部分专门化类,因此可以使用函子:

#include <iostream>

template <typename dtype, int k> struct fun
{
    int operator()()
    {
        return k;
    }
};

template <typename dtype> struct fun <dtype, 0>
{
    int operator()()
    {
        return 42;
    }
};

int main ( int argc , char * argv[] )
{
     std::cout << fun<float, 5>()() << std::endl;
     std::cout << fun<float, 0>()() << std::endl;
}

Since you can partially specialize classes, you can use a functor:

#include <iostream>

template <typename dtype, int k> struct fun
{
    int operator()()
    {
        return k;
    }
};

template <typename dtype> struct fun <dtype, 0>
{
    int operator()()
    {
        return 42;
    }
};

int main ( int argc , char * argv[] )
{
     std::cout << fun<float, 5>()() << std::endl;
     std::cout << fun<float, 0>()() << std::endl;
}
悸初 2024-10-26 00:14:13

由于两个原因,函数模板的部分特化会带来极大的问题。

函数模板重载的语法歧义

考虑完全特化的语法:

template <typename T>
void foo(T);

template <>
void foo(int); // full specialization; we could optionally write foo<int>(int)

template <> 语法,很明显这是一个完全特化,而不是非模板重载。
然而,对于部分特化来说就不太清楚了:

template <typename T>
void foo(std::complex<T>);

这可以解释为第二次重载,或者解释为部分特化 foo>(std::complex; )
如果这种歧义存在于语言中,将会非常令人困惑。

当存在多个重载时,即使是完整的特化也可能会造成混乱;请参阅 定义函数模板的显式特化时选择哪个重载?

特化不参与重载解析

template <typename T>
void foo();                                   // (0) primary template

template <>
void foo(std::complex<int>);                  // (1) full specialization

template <typename T>
void foo(std::complex<T>);                    // (2) overload

如果我们调用如果使用 std::complex 类型的参数,则调用 (2),而不是 (1),因为特化不参与重载解析。这是违反直觉的,因为 std::complexstd::complex “更专业”。

函数模板的完全特化和假设的部分特化的行为与直觉相反。函数模板重载是一个更有用的功能,在大多数情况下应该是首选。

解决方法 - 类模板的重载或部分特化

在大多数情况下,您可以简单地使用函数模板重载。
如果您需要紧密模仿部分特化,则可以改为编写函数对象:

// primary template
template <typename T>
struct foo_object {
    void operator()(T) const { /* ... */ }
};

// partial specialization
template <typename T>
struct foo_object<std::complex<T>> {
    void operator()(std::complex<T>) const { /* ... */ }
};

// convenience function
template <typename T>
void foo(T t) {
    return foo_object<T>{}(t);
}

与函数模板重载相比,一开始可能看起来毫无意义,但部分特化可以通过继承相互委托,这可能很有用。

这种模式是标签调度的可行替代方案。

另请参阅

Herb Sutter 的文章 为什么不专门化函数模板? 解释了有关显式专门化的问题细节。这些同样适用于假设的部分专业化。

Partial specializations of function templates would be extremely problematic for two reasons.

Syntactical ambiguity with function template overloading

Consider the syntax of a full specialization:

template <typename T>
void foo(T);

template <>
void foo(int); // full specialization; we could optionally write foo<int>(int)

From the template <> syntax, it is clear that this is a full specialization, not a non-template overload.
However, it would not be so clear for a partial specialization:

template <typename T>
void foo(std::complex<T>);

This could either be interpreted as a second overload, or as a partial specialization foo<std::complex<T>>(std::complex<T>).
This ambiguity would be extremely confusing if it existed in the language.

Even full specializations can be confusing when there are multiple overloads; see Which overload is selected when defining an explicit specialization of a function template?

Specializations don't participate in overload resolution

template <typename T>
void foo();                                   // (0) primary template

template <>
void foo(std::complex<int>);                  // (1) full specialization

template <typename T>
void foo(std::complex<T>);                    // (2) overload

If we call this with an argument of type std::complex<int>, then (2) is called, not (1), because specializations don't participate in overload resolution. This is counter-intuitive because std::complex<int> is "more specialized" than std::complex<T>.

Full specializations and hypothetical partial specializations of function templates behave contrary to intuition. Function template overloading is a much more useful feature, and should be preferred in most cases.

Workaround - Overloading, or partial specializations of class templates

In most cases, you can simply use function template overloading instead.
If you need to closely imitate partial specializations, you can write function objects instead:

// primary template
template <typename T>
struct foo_object {
    void operator()(T) const { /* ... */ }
};

// partial specialization
template <typename T>
struct foo_object<std::complex<T>> {
    void operator()(std::complex<T>) const { /* ... */ }
};

// convenience function
template <typename T>
void foo(T t) {
    return foo_object<T>{}(t);
}

It may seem pointless compared to function template overloading at first, but partial specializations can delegate to each other through inheritance, which may be useful.

Such a pattern is a viable alternative to tag dispatch.

See Also

Herb Sutter's article Why Not Specialize Function Templates? explains issues regarding explicit specializations in great detail. Those equally apply to hypothetical partial specializations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文