简体   繁体   English

模板类中模板函数的显式特化的 C++ 语法?

[英]C++ syntax for explicit specialization of a template function in a template class?

I have code which works in VC9 (Microsoft Visual C++ 2008 SP1) but not in GCC 4.2 (on Mac):我的代码适用于 VC9(Microsoft Visual C++ 2008 SP1)但不适用于 GCC 4.2(在 Mac 上):

struct tag {};

template< typename T >
struct C
{   
    template< typename Tag >
    void f( T );                 // declaration only

    template<>
    inline void f< tag >( T ) {} // ERROR: explicit specialization in
};                               // non-namespace scope 'structC<T>'

I understand that GCC would like me to move my explicit specialization outside the class but I can't figure out the syntax.我知道 GCC 希望我将我的显式专业化移到课堂之外,但我无法弄清楚语法。 Any ideas?有任何想法吗?

// the following is not correct syntax, what is?
template< typename T >
template<>
inline void C< T >::f< tag >( T ) {}

You can't specialize a member function without explicitly specializing the containing class.如果不明确专门化包含类,就无法专门化成员函数。
What you can do however is forward calls to a member function of a partially specialized type:但是,您可以将调用转发到部分专用类型的成员函数:

template<class T, class Tag>
struct helper {
    static void f(T);   
};

template<class T>
struct helper<T, tag1> {
    static void f(T) {}
};

template<class T>
struct C {
    // ...
    template<class Tag>
    void foo(T t) {
        helper<T, Tag>::f(t);
    }
};

GCC is in the clear, here. GCC 很清楚,在这里。 MSVC has a non-standard extension that allows in-class specialization. MSVC 有一个非标准扩展,允许进行类内专业化。 The standard, however, says:然而,该标准说:

14.7.3.2: 14.7.3.2:
2. An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class template is a member. 2. 显式特化应在模板所属的命名空间中声明,或者对于成员模板,应在封闭类或封闭类模板所属的命名空间中声明。 An explicit specialization of a member function, member class or static data member of a class template shall be declared in the namespace of which the class template is a member.类模板的成员函数、成员类或静态数据成员的显式特化应在类模板所属的命名空间中声明。

Additionally, you can't partially specialize a function.此外,您不能部分专门化一个函数。 (Though I'm unsure about the details in your case, that would be the final blow.) (虽然我不确定你案件的细节,但那将是最后一击。)

You could do this:可以这样做:

#include <iostream>

struct true_type {};
struct false_type {};

template <typename T, typename U>
struct is_same : false_type
{
    static const bool value = false;
};

template <typename T>
struct is_same<T, T> : true_type
{
    static const bool value = true;
};

struct tag1 {};
struct tag2 {};

template< typename T >
struct C
{
    typedef T t_type;

    template< typename Tag >
    void foo( t_type pX)
    {
        foo_detail( pX, is_same<Tag, tag1>() );
    }

private:
    void foo_detail( t_type, const true_type& )
    {
        std::cout << "In tag1 version." << std::endl;
    }
    void foo_detail( t_type, const false_type& )
    {
        std::cout << "In not tag1 version." << std::endl;
    }
};

int main(void)
{
    C<int> c;
    c.foo<tag1>(int());
    c.foo<tag2>(int());
    c.foo<double>(int());
}

Though this is somewhat ugly.虽然这有点难看。

Came across this question.遇到了这个问题。 This should work:这应该有效:

struct tag {};

template< typename T >
struct C {   
    template< typename Tag, typename std::enable_if<std::is_same<Tag, tag>::value, int>::type = 0>
    void f( T ){
        std::cout<<"tag type" <<std::endl;
    }

    template< typename Tag, typename std::enable_if<!std::is_same<Tag, tag>::value, int>::type = 0>
    void f( T ){
        std::cout<<"non tag type" <<std::endl;
    }
 };

I know this may not satisfy you, but I do not believe you may not have a specialization enclosed within a non-explicitly-specialized structure.我知道这可能不会让您满意,但我不相信您可能没有将专业化包含在非明确专业化的结构中。

template<>
template<>
inline void C< tag1 >::foo< tag2 >( t_type ) {}

The basic detail is that you need to put the code declaration outside of the class so that there is only one declaration of it.基本细节是您需要将代码声明放在类之外,以便只有一个声明。 If you leave it in a header, declared for all including c++ source files to see, you end up with multiple instances of the same class defined.如果你把它放在一个头文件中,声明所有包括 c++ 源文件都可以看到,你最终会定义同一个类的多个实例。 Just put the declaration of the templated function in the header file, and then move the declared specializations of that templated function into your C++ source file and all will be good because the compiler will generate the correct references based on the types of specialization you use in your source code.只需将模板化函数的声明放在头文件中,然后将该模板化函数的声明特化移动到您的 C++ 源文件中,一切都会好起来的,因为编译器会根据您使用的特化类型生成正确的引用你的源代码。

For example you want to create an extensible Number class like java's Number class so that you can pass numeric values around.例如,您想创建一个可扩展的 Number 类,如 java 的 Number 类,以便您可以传递数值。 If this is in the .h/.hpp file, the compiler will know how to generate references to each specialization because the return type is part of the generated function name that the compiler generates references for.如果这是在 .h/.hpp 文件中,编译器将知道如何生成对每个特化的引用,因为返回类型是编译器为其生成引用的生成函数名称的一部分。

class Number {
    Int32 intVal;
    double d;
    float  f;
    Int64 longVal;
    std::string strVal;
public:
    template<T>
    T getValue();
    ... other functions needed go here...
};

In your C++ source file you can just write the following.在您的 C++ 源文件中,您只需编写以下内容。

template<>
Int32 Number::getValue() { return intVal; }
template<>
double Number::getValue() { return d; }
template<>
float Number::getValue() { return f; }
template<>
Int64 Number::getValue() { return longVal; }
template<>
std::string Number::getValue() { return strVal; }

Now when you pass a Number around, depending on which value type you assign it to, you can use an appropriate value type on a getValue<>() calls.现在,当您传递一个数字时,根据您分配给它的值类型,您可以在 getValue<>() 调用上使用适当的值类型。

While the code is perhaps non-compliant, one practical solution is to switch to clang, where it works fine.虽然代码可能不合规,但一种实用的解决方案是切换到可以正常工作的 clang。

https://godbolt.org/z/hPbP1M https://godbolt.org/z/hPbP1M

gcc doesn't allow member function full specialization inside a class. gcc 不允许类内的成员函数完全专业化。 This is because functionality wise it is the same as function overloading.这是因为在功能方面它与函数重载相同。 So just remove template<> from specializations and make them function overloads instead.因此,只需从特化中删除 template<> 并使其成为函数重载即可。

From https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282 (Patrick Palka)来自https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282 (Patrick Palka)

[...] as a workaround, instead of eg: [...] 作为一种解决方法,而不是例如:

 struct A { template<class T> struct B; template<> struct B<int> { }; // unsupported class-scope explicit specialization };

in C++20 one can do:在 C++20 中可以做到:

 struct A { template<class T> struct B; template<std::same_as<int> T> struct B<T> { }; };

or in C++17:或在 C++17 中:

 struct A { template<class T, class = void> struct B; template<class T> struct B<T, std::enable_if_t<std::is_same_v<int,T>>> { }; };

尝试这个:

template <> template<typename T> inline void C<T> :: foo<tag2>(T) {}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM