我们正在使用奇怪的重复模板模式来实现单例.但是,在最近的Clang版本中,我们得到了一个-Wundefined-var-template警告.建议的修复是添加"显式实例化声明".
我试图这样做,但后来我在编译单元中获得了"实例化后显式特化"的错误,其中单例模板类成员变量的定义是.
解决此警告突出显示的问题的适当构造是什么?
简化细节(已删除大部分逻辑,以制作MCVE):
SingletonBase.hh:
template < class T > class SingletonBase {
public:
static T * get_instance() {
if ( ! instance_ ) {
instance_ = T::create_singleton_instance();
}
return instance_;
}
private:
static T * instance_;
};
Run Code Online (Sandbox Code Playgroud)
Singleton.hh:
#include "SingletonBase.hh"
class Singleton : public SingletonBase< Singleton > {
friend class SingletonBase< Singleton >;
public:
int do_stuff(int v) { return v+2; }
private:
static Singleton * create_singleton_instance() {
return new Singleton;
}
};
Run Code Online (Sandbox Code Playgroud)
Singleton.cc:
#include "Singleton.hh"
template …Run Code Online (Sandbox Code Playgroud) 我在C++中遇到问题,在调用派生类的函数的同时有一个指向基类的指针.
编辑:一些答案提到我CRTP
但我的观点是我需要一个指向"Base*"类而不是"Base*"的指针,因为我不知道当前正在处理的类型(当前实例是从某种工厂创建的).
class Base
{
..
template<typename T>
func (T arg) { ... };
};
class Derived1 : public Base
{
...
template<typename T>
func (T arg) { ... };
};
class Derived1 : public Base
{
...
template<typename T>
func (T arg) { ... };
};
Run Code Online (Sandbox Code Playgroud)
int main()
{
Base* BasePtr = new Derived1();
// The expected function to be called is Derived1::func<int>()
BasePtr->func<int>();
return 0; // :)
}
Run Code Online (Sandbox Code Playgroud)
我不能使func虚拟,因为该语言不支持虚拟模板功能.
仅当类只有模板参数时才允许,但如果其中的函数具有模板参数则不允许.
我已经看到在Boost.Serialization中解决了类似的问题,但无法理解解决方案.
谢谢,
Koby Meir
我真的不知道如何描述这个,但这是代码:
class A : public std::vector<A>
{
};
//....
A a;
a.push_back(a);
Run Code Online (Sandbox Code Playgroud)
它做了什么,为什么要这样做?
virtualC ++ 的主要优点之一是能够使用基类(指针或引用)来调用派生方法。
我正在阅读使用CRTP实现静态多态性的知识,但是我不明白如何使用该技术实现上面提到的内容,因为Base当需要模板时,我无法将函数声明为采用类型。
在我看来,仅通过使用函数重载就可以实现本文中描述的内容,因此,我敢肯定,该技术必须有更多的功能。
(PS:在回答该问题的评论中提到了这个确切的问题,但不幸的是没有人回答:“ vtables真正提供的功能是使用基类(指针或引用)来调用派生方法。您应该在此处显示如何使用CRTP进行操作。”)
这是我的最小代码,它给出错误“在'&'令牌无效Print(Base&Object)之前缺少模板参数”。
#include <cstring>
#include <iostream>
template <typename Derived>
struct Base
{
std::string ToStringInterface() { return static_cast<Derived*>(this)->ToString(); }
std::string ToString() { return "This is Base."; }
};
struct Derived : Base<Derived>
{
std::string ToString() { return "This is Derived."; }
};
void Print(Base& Object)
{
std::cout << Object->ToStringInterface() << std::endl;
}
int main()
{
Derived MyDerived;
// This works, but could have been achieved with a function …Run Code Online (Sandbox Code Playgroud) 阅读此答案后,我尝试实现一些简单的 CRTP 用法。我想我会尝试实现 Singleton(是的,我知道 - 这只是为了练习和研究)模式,因为链接的答案已经做到了这一点......除了它无法编译的事实。
引用的代码如下:
template <class ActualClass>
class Singleton
{
public:
static ActualClass& GetInstance()
{
if(p == nullptr)
p = new ActualClass;
return *p;
}
protected:
static ActualClass* p;
private:
Singleton(){}
Singleton(Singleton const &);
Singleton& operator = (Singleton const &);
};
template <class T>
T* Singleton<T>::p = nullptr;
class A: public Singleton<A>
{
//Rest of functionality for class A
};
Run Code Online (Sandbox Code Playgroud)
然后我将其“现代化”为:
template <class T>
class Singleton {
public:
Singleton() = delete;
Singleton(const Singleton&) …Run Code Online (Sandbox Code Playgroud) Mixins和函数模板是为多种类型提供行为的两种不同方式,只要这些类型满足某些要求即可.
例如,假设我想编写一些允许我将对象保存到文件的代码,只要这个对象提供了一个toString成员函数(这是一个相当愚蠢的例子,但请耐心等待).第一种解决方案是编写如下函数模板:
template <typename T>
void toFile(T const & obj, std::string const & filename)
{
std::ofstream file(filename);
file << obj.toString() << '\n';
}
...
SomeClass o1;
toFile(o1, "foo.txt");
SomeOtherType o2;
toFile(o2, "bar.txt");
Run Code Online (Sandbox Code Playgroud)
另一个解决方案是使用CRTP使用mixin :
template <typename Derived>
struct ToFile
{
void toFile(std::string const & filename) const
{
Derived * that = static_cast<Derived const *>(this);
std::ofstream file(filename);
file << that->toString() << '\n';
}
};
struct SomeClass : public ToFile<SomeClass>
{
void toString() const {...}
};
...
SomeClass …Run Code Online (Sandbox Code Playgroud) 我正在开发一个迭代器系列,其中所有迭代器类X都有X& operator++() {++x; return *this}共同点,因此将它放在一个公共基类中似乎是个好主意.不幸的是,返回类型会发生变化,因为它应该始终返回对派生类的引用.
以下说明了这个问题.我想f()工作,但唯一的解决方法我能想出是g()和h(),这是不令人满意的:
struct A {
A& f() {return *this;}
template <typename T>
T& g() {return *(T*)this;}
template <typename T>
T& h(T& unused) {return *(T*)this;}
};
struct B : A {
int x;
B(int x) : x(x) {}
};
int main() {
B b(12);
//B b1 = b.f(); // error: conversion from 'A' to non-scalar type 'B' requested
B b2 = b.g<B>(); // works
B b3 = …Run Code Online (Sandbox Code Playgroud) 在 C++11 下测试库时,我在 Clang 下收到警告。我以前从未遇到过警告,搜索并没有提供太多的阅读和研究方式。
警告如下所示,它似乎与多重继承和公共基类有关。但我不清楚触发警告的细节或我应该做些什么来解决它。
我的第一个问题是,这是一个需要解决的问题吗?还是仅仅是效率问题?
我的第二个问题是(如果需要),如何解决警告?或者有哪些可用于修复它的选项?
以下是一些附加信息:
还在 Stack Overflow 上回顾了以下内容,但我不清楚它们在哪里相交:
库Crypto++也大量使用Curiously Recurring Template Pattern进行编译时多态性。
头文件可在线获取,这里是实际警告:
g++ -DDEBUG -g2 -O2 -std=c++11 -Wno-deprecated-declarations -fPIC -march=native -pipe -c rsa.cpp
In file included from rsa.cpp:4:
In file included from ./rsa.h:12:
./pubkey.h:635:26: warning: defaulted move assignment operator of 'InvertibleRSAFunction' will move assign …Run Code Online (Sandbox Code Playgroud) 我正在为数学库创建自己的向量结构。
目前,我会创建类似于这样的结构:
template <unsigned int size, typename T>
struct vector {
// array of elements
T elements[size];
// ...
};
Run Code Online (Sandbox Code Playgroud)
然而,数学库的主要用例将导致主要使用 2 维、3 维和 4 维向量(通常为vec2、vec3和vec4)。因此,一个有用的功能是能够在可能的情况下从向量访问 x、y、z 和 w 值。然而,这也存在一些问题。
、x、和成员需要是、等的引用变量。这意味着,如果向量的元素少于 4 个,则某些引用将不会被初始化y。zwelements[0]elements[1]
当然,这可以通过专门的模板来实现,这就是我目前正在做的:
template <unsigned int size, typename T>
struct vector {
// ...
}
template <typename T>
struct vector<2, T> {
// same as with before, except with references to X and …Run Code Online (Sandbox Code Playgroud) 我想做一些在 Cpp 中可能无法实现的事情,但我找不到专门针对此的帖子。
我想让派生类指定虚函数上的 void* 参数的类型。
我有一个名为 interface 的基类,带有一个发送函数。
// pure virtual
class Interface{
virtual bool Send(const void*)=0;
};
struct Packet{
DataType data;
};
class SpecificInterface{
bool Send(const DataType*);
}
Run Code Online (Sandbox Code Playgroud)
有没有办法让这样的工作?意图是SpecificInterface::Send 实现Interface::Send。允许特定接口不是纯虚拟的,同时将 void* 限制为特定的数据包类型。
否则我知道我可以使用 void* 参数并将其 static_cast 转换为 Packet* 类型;但是,我不希望其他人发送无法转换为 Packet* 的指针类型。
如果这不清楚,请告诉我