I have the following class:
template <typename T>
class Fixed2DContainer {
T* ptr;
public:
const int total_cols;
const int total_rows;
Fixed2DContainer(int cols, int rows);
T& operator()(int col_n, int row_n);
~Fixed2DContainer();
private : //disallow copy
Fixed2DContainer& operator=(const Fixed2DContainer&);
Fixed2DContainer operator()(const Fixed2DContainer&);
};
Now I'd like to specialize this template for some class so that the only change is that I can have an another constructor.
Basically I want to be able to do:
Fixed2DContainer<Image>("filename.jpg");
is there an elegant way to do this? I am fairly new to template so i have no idea of the difficulty
If your compiler supports it, C++11 has inheriting constructors that will pretty much get you where you want to be:
template <typename T>
class Base {}; // has all the implementation
template <typename T>
class Template {
using Base::Base;
//Template() = delete; // You might need this if you don't want
// the default constructor
};
template <>
class Template<int> {
using Base::Base;
Template( std::string const & x ) {}
//Template() = delete; // You might need this if you don't want
// the default constructor
};
Here's a quick example of what I meant in my earlier comment ...
template <typename T>
class Fixed2DContainerBase {
T* ptr;
public:
const int total_cols;
const int total_rows;
Fixed2DContainerBase(int cols, int rows);
T& operator()(int col_n, int row_n);
~Fixed2DContainerBase();
private : //disallow copy
Fixed2DContainerBase& operator=(const Fixed2DContainerBase&);
Fixed2DContainerBase(const Fixed2DContainerBase&);
};
// primary template
template <typename T>
class Fixed2DContainer : public Fixed2DContainerBase<T> {
Fixed2DContainer(int cols, int rows);
~Fixed2DContainer();
};
// explicit specialization
template <>
class Fixed2DContainer<Image> : public Fixed2DContainerBase<Image> {
Fixed2DContainer(int cols, int rows);
Fixed2DContainer(const std::string&);
~Fixed2DContainer();
};
N.B. because the base class is non-copyable the derived classes will be too. It may not be necessary to define a destructor in the derived classes if all the cleanup can be done by the base destructor.
I have had the same problem myself. Unfortunately, every constructor must exist in the generic template. You can avoid people using the wrong constructor at runtime though;
template <typename T>
class Fixed2DContainer {
// omitted
Fixed2DContainer(string fileName)
{
// Do not allow construction of Fixed2DContainer with
// string argument in general case
ASSERT(false);
// or
throw new ExceptionType("Not implemented");
}
// omitted
};
template<>
class Fixed2DContainer<Image> {
// omitted
Fixed2DContainer(string fileName)
{
// Actual construction code
}
// omitted
};
Asserts are preferred because your code will break on the assert whereas the in the exception case it will break on the catch, making it slightly harder to debug.
Related
In a templated class, can we check a member function's signature and define different compilation behaviors for different subclasses? To be more specific, consider the following simple example:
template <typename T>
class Foo {
// ingore all other functions
virtual std::shared_ptr<T> do_something(int a) {
return std::make_shared<T>(a);
}
};
This should just work fine with the T1 class:
class T1 {
T1(int a) {
// implememntation
}
// ingore all other functions
};
// Foo<T1> would just work
However, it will fail the compilation with T2 because Foo's do_something function is clearly implemented to call T's constructor with one argument only:
class T2 {
T2(int a, int b) {
// implememntation
}
// ingore all other functions
};
// Foo<T2> would fail to compile
So the question is, can we rework on Foo to let it work for both T1 and T2, in the way that, for T1 and classes whose constructor takes one int argument, it will compile with a default implementation, whereas for T2 and classes whose constructors are different, it will compile with a virtual function and enforce subclass to implement it with override. Somewhat like below:
Template <typename T>
class Foo {
// ingore all other functions
/* if T's signature takes one int input only
* compile like the below
*/
virtual std::shared_ptr<T> do_something(int x) {
return std::make_shared<T>(x);
}
/* if T's signature is different
* compile like the below and let the subclass implement it
*/
virtual std::shared_ptr<T> do_something(int x) = 0;
}
Is this possible without using any 3rd-party library? It's acceptable if we have to use macros/preprocessors.
It is also acceptable if there must be one function do_something there but for the case of mismatched signature, it just raises runtime exception, something like:
Template <typename T>
class Foo {
// ingore all other functions
virtual std::shared_ptr<T> do_something(int x) {
/* if T's signature takes one int input only
* compile like the below
*/
// return std::make_shared<T>(x);
/* if T's signature is different
* compile like the below and let the subclass implement it
*/
// std::throws...
}
}
As far as I can tell, we need class template specialization here. Not even C++20 requires-clauses can be applied to virtual functions, so the only thing we can do is have the whole class change.
template<typename T> // using C++20 right now to avoid SFINAE madness
struct Foo {
virtual ~Foo() = default;
virtual std::shared_ptr<T> do_something(int a) = 0;
};
template<std::constructible_from<int> T>
struct Foo<T> {
virtual ~Foo() = default; // to demonstrate the issue of having to duplicate the rest of the class
virtual std::shared_ptr<T> do_something(int a) {
return std::make_shared<T>(a);
}
};
If there is a lot of stuff in Foo, you can avoid duplicating it with a heap of upfront cost by moving do_something to its own class.
namespace detail { // this class should not be touched by users
template<typename T>
struct FooDoSomething {
virtual ~FooDoSomething() = default;
virtual std::shared_ptr<T> do_something(int a) = 0;
};
template<std::constructible_from<int> T>
struct FooDoSomething<T> {
virtual ~FooDoSomething() = default;
virtual std::shared_ptr<T> do_something(int a);
};
}
template<typename T>
struct Foo : detail::FooDoSomething<T> {
// other stuff, not duplicated
// just an example
virtual int foo(int a) = 0;
};
namespace detail {
template<std::constructible_from<int> T>
std::shared_ptr<T> FooDoSomething<T>::do_something(int a) {
Foo<T> &thiz = *static_cast<Foo<T>*>(this); // if you need "Foo things" in this default implementation, then FooDoSomething is *definitely* unsafe to expose to users!
return std::make_shared<T>(thiz.foo(a));
}
}
Godbolt
To convert this down from C++20, replace the concept-based specialization with old-type branching:
// e.g. for the simple solution
template<typename T, bool = std::is_constructible_v<T, int>>
struct Foo { // false case
// etc.
};
template<typename T>
struct Foo<T, true> { // true case
// etc.
};
// or do this to FooDoSomething if you choose to use that
A runtime error is much easier, at least in C++17 and up, since you can just use a if constexpr to avoid compiling the problematic code
template<typename T>
struct Foo {
virtual ~Foo() = default;
virtual std::shared_ptr<T> do_something(int a) {
if constexpr(std::is_constructible_v<T, int>) return std::make_shared<T>(a);
else throw std::logic_error("unimplemented Foo<T>::do_something");
}
};
Is there a way to encapsulate a type in a template class (akin to something like std::optional) that has all the necessary special constructors and assignment operators (i.e. copy ctor/assignment, move ctor/assignment) but only "enables" them if the underlying type has those functions? The functions in type_traits like std::is_copy_constructible look like they might help but I'm not sure how to use them to achieve this goal. For reference, the type I'm trying to implement is similar to std::optional but instead of the alternate value being simply "none" I want to use a custom error type. E.g.
template <typename T>
class ErrorOr {
public:
enum class Error {
FATAL,
WARNING,
NONE,
};
ErrorOr(T val) : val(val), error(Error::NONE) {}
ErrorOr(Error error) : error(error) {}
// TODO: Implement copy/move ctors/assignment operators that only
// exist if they do for the underlying T
T get() { val; }
private:
T val;
Error error;
};
This is a very bare-bones/minimal implementation that doesn't have a lot of the necessary features but hopefully illustrates the point I'm trying to make.
Is this possible in C++11?
In this case, do nothing. ErrorOr<T> having a member of type T will default all the special member functions to do the Right Thing. If T isn't copyable, ErrorOr<T> won't be either.
However, this also isn't really an optional type since you always have a T. If you eventually move to an implementation which conditionally has a T,
one way to do this would be to inherit from an empty type that either enables or disables the special members as appropriate.
A simplified version would be:
template <bool allowCopies>
struct copy_enabler {
copy_enabler() = default;
copy_enabler(copy_enabler const& ) = default;
copy_enabler& operator=(copy_enabler const& ) = default;
};
template <>
struct copy_enabler<false> {
copy_enabler() = default;
copy_enabler(copy_enabler const& ) = delete;
copy_enabler& operator=(copy_enabler const& ) = delete;
};
Then you can simply:
template <typename T>
class ErrorOr : private copy_enabler</* is T copyable */> { ... };
In practice, you will want to do this for all the special member functions, and also add a tag type so that if you use this trick for multiple different class templates, they don't end up sharing a common base.
In the following code, class X has a copy constructor defined only if its template argument is of a class type and is copy-constructible (which means that it should have copy constructor):
template <typename T>
class X {
static constexpr bool has_copy_constructor
= std::is_class<T>::value && std::is_copy_constructible<T>::value;
struct dummy_type { };
public:
X() = default;
X(typename std::conditional<has_copy_constructor,
const X &, const dummy_type &>::type) { std::cerr << "copy ctor\n"; }
X(typename std::conditional<has_copy_constructor,
const dummy_type &, const X &>::type) = delete;
};
int main() {
X<std::string> x1;
X<std::string> x2(x1); // OK
X<int> x3;
X<int> x4(x3); // ERROR
}
Not that I like this solution, but it kind of works.
Yes, use std::enable_if (std::enable_if_t in newer c++ versions, not sure if that was added in c++11).
template<typename T>
struct my_type
: T
{
my_type(T && val, typename std::enable_if<std::is_move_constructible<T>::value>::type * = nullptr)
: T(std::move(val))
{
}
};
I'm working on a project in C++ and am having trouble understanding what members of a template class get explicitly instantiated when I explicitly instantiate the template class. I've written the following file, which I then compile using Visual C++ 2008 Express Edition's Release configuration and then pop into a disassembler.
template<typename T> class test {
public:
template<typename T> test(T param) {
parameter = param;
};
~test() {};
int pop();
int push();
T parameter;
};
template<typename T> int test<T>::push() {return 1;}
template<typename T> int test<T>::pop() {return 2;}
template class test<int>;
int main() {
return 0;
}
Ignoring that this file doesn't really need templates for the moment, this compiles fine. I throw the exe into the disassembler and it tells me that test<int>::pop(void), test<int>::push(void), and test<int>::~test<int>(void) are functions in the exe, but I don't see the constructor. I know I can explicitly instantiate the constructor with
template test<int>::test(int);
which causes test<int>::test<int>(int) to appear in the disassembly as a function with the other ones. My understanding of explicit instantiation is that it is supposed to tell the compiler to instantiate all members of a template class for a given set of arguments, so why is it that the constructor is not explicitly instantiated along with all the other member functions?
When the constructor is a template member function, they are not instantiated unless explicitly used.
You would see the code for the constructor if you make it a non-template member function.
template<typename T> class test {
public:
/***
template<typename T> test(T param) {
parameter = param;
};
***/
test(T param) : parameter(param) {}
~test() {}
int pop();
int push();
T parameter;
};
When I try to compile this with Clang
template<class T>
struct Field
{
char const *name;
Field(char const *name) : name(name) { }
};
template<class Derived>
class CRTP { static Field<Derived> const _field; };
class Class : public CRTP<Class> { };
Field<Class> const CRTP<Class>::_field("blah");
int main() { }
I get
error: template specialization requires 'template<>'
Field<Class> const CRTP<Class>::_field("blah");
~~~~~~~~~~~ ^
I don't understand the error at all. What is wrong with my definition of _field and how do I fix it?
(Note that the arguments to _field are not necessarily the same for all subclasses.)
For the compiler to identify this as a template specialization (e.g. to be able to check the syntax), you need the template keyword:
template<>
Field<Class> const CRTP<Class>::_field("blah");
Its brackets are empty as all template parameters are specialized, but you cannot just leave it away.
The error says exactly what is missing. template<> is missing before that line.
template<>
Field<Class> const CRTP<Class>::_field("blah");
Note, however, that your typing of Field<Class>, if unique, could be used to construct all instances of Field<Class> with a given string.
template<typename T>
struct field_trait;
template<class T>
struct Field
{
char const *name;
Field() : name(field_trait<T>::get_name()) {}
};
template<class Derived>
class CRTP { static Field<Derived> const _field; };
template<class Derived>
class CRTP<Derived>::_field;
class Class;
template<>
struct field_traits<Class> {
static const char* get_name() { return "blah"; }
};
class Class : public CRTP<Class> { };
int main() { }
which means that every instance of Field<Class> always has the name "blah".
One question I would have is, do you really need storage for said Field<Class> to actually have a pointer to a string, and if so does it need to be unique, and if so does it need to be "bare"? Because figuring out where the static instance exists is somewhat annoying.
Together with field_traits above:
template<class Derived>
class CRTP { static Field<Derived>& field() const { static Field<Derived> _field( field_traits<Derived>::get_name()); return _field; };
this moves the problem of "where is the _field stored" to being the compilers problem. And it is initialized by the contents of field_traits<T>::get_name().
A static data member must have both a declaration and a definition. If this was a plain class it would look like this:
// header:
class C {
static int i;
};
// source:
int C::i = 3;
Templates aren't ordinarily defined in source files, so the code would look something like this:
// header:
template <class T>
class C {
static int i;
};
template <class T>
int C<T>::i = 3;
In your code, you don't have the definition of the static data member. That's okay if you don't use it. But the code that the compiler is complaining about defines a static data member for CRTP<Class>; that's a specialization (because it's not applicable to all instantiations of CRTP, just to this one), and the compiler is saying that you have to tell it that it's a specialization. So do as you're told:
template <>
Field<Class> const CRTP<Class>::_field("blah");
or, to write the non-specialized template version, use the usual template syntax:
template <class T>
Field<T> const CRTP<T>::_field("blah");
I'm looking for a better way to this. I have a chunk of code that needs to handle several different objects that contain different types. The structure that I have looks like this:
class Base
{
// some generic methods
}
template <typename T> class TypedBase : public Base
{
// common code with template specialization
private:
std::map<int,T> mapContainingSomeDataOfTypeT;
}
template <> class TypedBase<std::string> : public Base
{
// common code with template specialization
public:
void set( std::string ); // functions not needed for other types
std::string get();
private:
std::map<int,std::string> mapContainingSomeDataOfTypeT;
// some data not needed for other types
}
Now I need to add some additional functionality that only applies to one of the derivative classes. Specifically the std::string derivation, but the type doesn't actually matter. The class is big enough that I would prefer not copy the whole thing simply to specialize a small part of it. I need to add a couple of functions (and accessor and modifier) and modify the body of several of the other functions. Is there a better way to accomplish this?
Impose another level of indirection in the template definitions:
class Base
{
// Generic, non-type-specific code
};
template <typename T> class TypedRealBase : public Base
{
// common code for template
};
template <typename T> class TypedBase : public TypedRealBase<T>
{
// Inherit all the template functionality from TypedRealBase
// nothing more needed here
};
template <> class TypedBase<std::string> : public TypedRealBase<T>
{
// Inherit all the template functionality from TypedRealBase
// string-specific stuff here
}
You don't have to specialize the whole class, only what you want. Works with GCC & MSVC:
#include <string>
#include <iostream>
class Base {};
template <typename T>
class TypedBase : public Base
{
public:
T get();
void set(T t);
};
// Non-specialized member function #1
template <typename T>
T TypedBase<T>::get()
{
return T();
}
// Non-specialized member function #2
template <typename T>
void TypedBase<T>::set(T t)
{
// Do whatever here
}
// Specialized member function
template <>
std::string TypedBase<std::string>::get()
{
return "Hello, world!";
}
int main(int argc, char** argv)
{
TypedBase<std::string> obj1;
TypedBase<double> obj2;
std::cout << obj1.get() << std::endl;
std::cout << obj2.get() << std::endl;
}