C++是否支持单个泛型方法而不是泛型类?

Nic*_*ton 6 c# c++ templates

重要提示:这个问题已经很长了,如果这是你第一次阅读这篇文章我建议你从底部开始,因为解决方案是在一个回合的方式,但代码有点臭.

阅读完模板教程后,我能够更改现有类以支持泛型类型.但是,许多对象已经依赖于此,所以我正在寻找一种使方法通用而不是整个类的方法.

我尝试了以下内容,但看起来不支持此行为.

// foobar1.h
// Don't want the entire class to be generic.
//template<class T>
class FooBar1
{
public:
    template<class T> T Foo();
}

// foobar2.h
class FooBar2 : public FooBar1
{
}

// foobar1.cpp
template<class T>
T FooBar1::Foo()
{
    return something;
}

// test.cpp
FooBar1 fb1;
FooBar2 fb2 = fb1.Foo<FooBar2>();
Run Code Online (Sandbox Code Playgroud)

这应该不起作用,还是我在其他地方遇到的一个错误?

未定义的引用 FooBar2 Foo<FooBar2>()

为了实现我想要实现的目标,我在C#中如何做到这一点......

public class FooBar1
{
    public T Foo<T>()
        where T : FooBar1
    {
        return something;
    }
}

public class FooBar2 : FooBar1 { }

FooBar1 fb1 = new FooBar1();
FooBar2 fb2 = fb1.Foo<FooBar2>();
Run Code Online (Sandbox Code Playgroud)

有什么方法可以做类似于C++的东西吗?

更新1:

刚刚纠正了一些小的语法细节(我的意思是让Foo公开,然后返回T,而不是FooBar2).仍然得到编译器错误...当我删除模板行为时,错误消失了,到目前为止答案说我正在做的是有效的...但如果是,那么为什么我仍然得到错误?谢谢你的回答!

更新2:

Josh,这是实际的源代码(嗯,我认为是相关的,anwyay - 如果你认为我已经跳过了重要的一点,请告诉我).

// ImageMatrix.h
class ImageMatrix : public VImage
{
public:
    // ... various functions ...
    template<class T> T GetRotatedCopy(VDouble angle);
}

// ImageFilter.h
class ImageFilter : public ImageMatrix
{
    // ... various functions ...
}

// ImageMatrix.cpp
template<class T>
T ImageMatrix::GetRotatedCopy(VDouble angle)
{
    // ... create a new instance of ImageMatrix and return it.
}

// ImageProcessor.cpp
ImageFilter filter2 = filterPrototype.GetRotatedCopy<ImageFilter>(90);
Run Code Online (Sandbox Code Playgroud)

这是实际的编译器错误:

/home/nick/Projects/ViMRID/vimrid/Debug/libvimrid.so:vimrid :: imaging :: processing :: ImageFilter vimrid :: imaging :: ImageMatrix :: GetRotatedCopy(double)'的未定义引用

更新3:

顺便说一下,除了实现线之外的所有东西都位于一个库中; 所以它是从一个单独的二进制文件调用的......这有关系吗?更正; 它都在同一个图书馆里.但是所有块都是不同的文件.

更新4:

当我注释掉实现行(ImageFilter filter2 = filterPrototype ...)时,它构建得很好,所以看起来就是这一行导致它......

更新5(已解决?):

还有问题......这可能是命名空间的问题吗?抓紧,好吧,我现在已经掌握了模板的概念!:)模板定义必须与声明一起在标题中(对吗?) - 所以现在我已经将声明移到了ImageMatrix.h,所有内容都编译完成.但是,我不得不使用dynamic_cast它来使它工作; 这是正确的吗?如果我要离开,请纠正我!

// This is in the header file!
// Help!!! This looks really really smelly...
template<class T>
T ImageMatrix::GetRotatedCopy(VDouble angle)
{
    ImageMatrix image = _getRotatedCopy(angle);
    ImageMatrix *imagePtr = &image;
    return *dynamic_cast<T*>(imagePtr);
}
Run Code Online (Sandbox Code Playgroud)

更新6:

参考更新5,当我不使用dynamic_cast时......

template<class T>
T ImageMatrix::GetRotatedCopy(VDouble angle)
{
    ImageMatrix image = _getRotatedCopy(angle);
    ImageMatrix *imagePtr = &image;
    //return *dynamic_cast<T*>(imagePtr);
    return *imagePtr;
}
Run Code Online (Sandbox Code Playgroud)

......我收到这个错误......

../src/imaging/processing/../ImageMatrix.h: In member function ‘T vimrid::imaging::ImageMatrix::GetRotatedCopy(vimrid::VDouble) [with T = vimrid::imaging::processing::ImageFilter]’:
../src/imaging/processing/ImageProcessor.cpp:32:   instantiated from here
../src/imaging/processing/../ImageMatrix.h:45: error: conversion from ‘vimrid::imaging::ImageMatrix’ to non-scalar type ‘vimrid::imaging::processing::ImageFilter’ requested
make: *** [src/imaging/processing/ImageProcessor.o] Error 1
Run Code Online (Sandbox Code Playgroud)

更新7:

另外,如果我在更新6中没有使用所有那些臭臭的代码......

class ImageMatrix : public VImage
{
public:
    template<class T> T GetRotatedCopy(VDouble angle);
private:
    ImageMatrix _getRotatedCopy(VDouble angle);
};

template<class T>
T ImageMatrix::GetRotatedCopy(VDouble angle)
{
    return _getRotatedCopy(angle);
}
Run Code Online (Sandbox Code Playgroud)

...我得到了与更新6中相同的错误.

Ecl*_*pse 11

是的,你非常接近,试试这个:

class FooBar1
{
public:
    template<class T> T Foo();
};

class FooBar2 : public FooBar1
{
};

template<class T>
T FooBar1::Foo()
{
    return T();
}

int main()
{
   FooBar1 fb1;
   FooBar2 fb2 = fb1.Foo<FooBar2>();
}
Run Code Online (Sandbox Code Playgroud)

您遇到的问题是您指定的返回类型为FooBar1::Foo()as FooBar2,您应该将其设置为just T.

如果你想为FooBar2做特定的事情,你可以专门研究FooBar2:

template<>
FooBar2 FooBar1::Foo<FooBar2>()
{
    return FooBar2();
}
Run Code Online (Sandbox Code Playgroud)

编辑:听起来你在编译器没有找到模板化GetRotatedCopy的定义时遇到问题.C++中的模板相当挑剔,通常的做法是将整个模板实现放在头文件中.你可以试试这个:

class ImageMatrix : public VImage
{
public:
    // ... various functions ...
    template<class T> T GetRotatedCopy(VDouble angle)
    {
       // ... create a new instance of ImageMatrix and return it.
    }
};
Run Code Online (Sandbox Code Playgroud)

编辑:我找不到gcc文档,但这里是microsoft关于显式模板实例化和库的文档,它给出了一些关于发生了什么的想法.您可能希望按照我之前的建议在头中包含实现,或者在库中调用GetRotatedCopy,或者在库中显式实例化它.有关语法,请参阅下面的veefu答案.

这与C#的不同之处在于,与C#不同,C++中的模板实际上为每个不同的模板参数组合创建了一个全新的类/函数.例如,vector<int>是一个完全不同的类(使用不同的编译方法集)vector<string>.请参阅凯文的答案以获得更好的解释.

至于当你不使用模板时错误消失,这实际上并没有告诉你多少,因为直到你实际实例化一个模板,它不会

RE更新5,6,7

您的dynamic_cast不起作用,只有当指针实际指向您要转换的类的实例时,才能使用它.(它与asC#中的运算符类似).

我现在怀疑,你想要的是CRTP.您从ImageFilter的实例开始,并希望在其上使用基类方法,并获取ImageFilter的新副本.尝试这些方面:

template <class T>
class ImageMatrix
{
public:
    T GetRotatedMatrix()
    {
        return T();
    }
};

class ImageFilter : public ImageMatrix<ImageFilter>
{
};

int main()
{
    ImageFilter filterPrototype;
    ImageFilter otherFilter = filterPrototype.GetRotatedMatrix();
}
Run Code Online (Sandbox Code Playgroud)

否则,如果您真的想从ImageMatrix开始并将其转换为ImageFilter,则必须在ImageFilter上添加一个构造函数,该构造函数采用ImageMatrix.