Playing with C++ 20 modules, I have the following snippet:
export {
template<class T>
class Suite {
private:
std::vector<ConcreteBuilder<T>> things {};
};
template <class T>
class ConcreteBuilder : Builder<T> {
private:
// A collection of things of function pointers or functors
std::vector<std::function<void()>> things;
public:
// Virtual destructor
virtual ~TestBuilder() override {};
// Add a new thing to the collection of things
template<typename Function>
void add(Function&& fn) {
tests.push_back(std::forward<Function>(fn));
}
// override the build() base method from Builder<T>
virtual T build() const override {
return this->things;
}
};
}
And I am getting this Clang error:
error: use of undeclared identifier 'ConcreteBuilder'
std::vector<ConcreteBuilder> things {};
Why I can't access to a type that are in the same module at the same level?
The compiler compiles the file from the top down, not all at once. It is hitting the definition of std::vector<ConcreteBuilder<T>> before it gets to the definition of class ConcreteBuilder.
So, you need to move your definition of Suite after the definition of ConcreteBuilder, so the compiler knows what it is when you use it in the vector definition.
Related
I am still learning C++ hard and have now generated a circular dependency that, according to C2039: Class is not a member of Namespace may be the cause to my issue that I get a C2039 error. Can somebody help me how to cut this circle?
I have two template classes and the template class tXmlGeometry<Part> has a member function that shall declare an instance of template class tXmlStraightLine. Both are inside namespace nXml but the compiler complains that tXmlStraightLine is not member of nXml.
I have to say that I bound the tXmlGeometry.h into the tXmlStraightLine header but I get an error when I try to bind the tXmlStraightLine.h into the tXmlGeometry header at the same time. I also just tried to remove the #include nXml/tXmlGeometry from the tXmlStraightLine header to no avail.
So here's a simplified code for the tXmlGeometry template class inside namespace nXml:
namespace nXml
{
template<class Part>
class tXmlGeometry : public tXmlNode<Part>
{
public:
tXmlGeometry(Part* part);
~tXmlGeometry();
void AddStraightLine2D(const pugi::xml_node& node) {};
};
}
;
and the implementation of the AddStraightLine2D method that causes the issue:
template<class Part>
inline void nXml::tXmlGeometry<Part>::AddStraightLine2D(const pugi::xml_node& this_node)
{
nXml::tXmlStraightLine<Part> straightline_xml(this);
//do more stuff
}
Here's the simplified code for the tXmlStraightLine template class:
namespace nXml
{
template<class Part>
class tXmlStraightLine : public tXmlSegment2D<Part>
{
public:
tXmlStraightLine(tXmlGeometry<Part>* geo, const int npos);
~tXmlStraightLine();
}
;
}
;
Can somebody advice me how to avoid that circular dependency?
EDIT: I corrected an error in member function naming.
Since they're both template classes, I'd consider placing them in the same header.
In order to avoid dependency issues, you can separate the declarations and definitions. Something like this:
namespace nXml
{
// tXmlGeometry<Part> declaration
template<class Part>
class tXmlGeometry : public tXmlNode<Part>
{
public:
tXmlGeometry(Part* part);
~tXmlGeometry();
inline void AddStraightLine2D(const pugi::xml_node& this_node);
};
// tXmlStraightLine declaration
template<class Part>
class tXmlStraightLine : public tXmlSegment2D<Part>
{
public:
tXmlStraightLine(tXmlGeometry<Part>* geo, const int npos);
~tXmlStraightLine();
};
// tXmlGeometry<Part> definitions
template<class Part>
inline void nXml::tXmlGeometry<Part>::AddStraightLine2D(const pugi::xml_node& this_node)
{
nXml::tXmlStraightLine<Part> straightline_xml(this);
//do more stuff
}
}
;
Is the following code legal C++?
MS Visual C++ fails, but gcc and clang are fine: https://godbolt.org/z/vsQOaW
It could be an msvc bug, but wanted to check first:
struct Base {
virtual void junk() = 0;
};
template <class T>
struct Derived : Base {
void junk() override {
T::junkImpl();
}
void otherMethod() {
}
};
template <class T>
struct NotDerived {
void junk() {
T::junkImpl();
}
void otherMethod() {
}
};
struct TypeWithJunk {
void junkImpl() {
}
};
struct TypeWithoutJunk {};
void reproduce(NotDerived<TypeWithoutJunk>* ndt, Derived<TypeWithoutJunk>* dt) {
// works - junk is not used, not instantiated
ndt->otherMethod();
// fails on MSVC - junk is instantiated even if not used
dt->otherMethod();
}
junk may get instantiated just like the rest of virtual functions because it is required to populate vtable. So all the compilers seem to demonstrate conforming behavior:
17.8.1 Implicit instantiation [temp.inst]
9 … It is unspecified
whether or not an implementation implicitly instantiates a virtual member function of a class template if
the virtual member function would not otherwise be instantiated.
I have a base class template which has 2 parameters, T is the derived class, flag means I want to activate some feature, default as false:
template
<
typename T,
bool flag
>
class SomeBase
{
public:
static Info& GetInfo()
{
static Info& instance = CreateInfo<T>(T::ClassName());
static bool inited = false;
if (!inited)
{
Test<flag>(instance);
inited = true;
}
return instance;
}
private:
template<bool enable>
static void Test(Info& instance)
{
return;
}
template<>
static void Test<true>(Info& instance)
{
T::Add(fields);
}
};
and to use this base:
class /*dllexport*/ MyClass : public SomeBase<MyClass, false>
{
public:
// ...
};
The flag template parameter is set to false, so according to my specialization, it should compiles the upper empty function, and the compiler does it, which is fine.
But, if I add dllexport to MyClass, then the compiler is giving C2039, which says 'Add' is not a member of MyClass, which doesnt make sense, because I am using SomeBase as flag == false.
Why does adding dllexport makes compiler try to compile the wrong specialization?
////////////////////////////////////////
Edit 1:
////////////////////////////////////////
According to this link:
http://msdn.microsoft.com/en-us/library/twa2aw10%28v=vs.100%29.aspx
Is the statement when one or more of the base classes is a specialization of a class template talking about SomeBase<MyClass, false>?
If so, the compiler implicitly applies dllexport to the specializations of class templates means the compiler is adding dllexport to SomeBase<MyClass, false>.
And, since I've already fully specialized static void Test(Info& instance), the compiler should choose the correct version of Test(), which is Test<false>().
So how come it is choosing(or compiling) the wrong version (Test<true>())?
Thanks!
Without dllexport, you will get the same error when you invoke MyClass::GetInfo from main.
In this case, compiler is expanding and compiling only part code that is invoked.
But with dllexport, it expands and compiles everything.
You can validate with this
template <typename T>
class SomeBase
{
public:
void test()
{
dafsaf;
}
private:
};
class /*__declspec(dllexport)*/ MyClass : public SomeBase<MyClass>
{
public:
// ...
};
int main()
{
MyClass o;
//o.test();
return 1;
}
I've encountered a problem(error C2761) while writing specializations for a class. My classes are as follows:
class Print{
public:
typedef class fontA;
typedef class fontB;
typedef class fontC;
typedef class fontD;
template<class T>
void startPrint(void) { return; };
virtual bool isValidDoc(void) = 0;
};
I have a class QuickPrint which inherits the Print class:
class QuickPrint : public Print {
...
};
The error occurs when I try to write specializations for the startPrint method:
template<> // <= C2716 error given here
void QuickPrint::startPrint<fontA>(void)
{
/// implementation
}
template<> // <= C2716 error given here
void QuickPrint::startPrint<fontB>(void)
{
/// implementation
}
The error appears for the remaining specializations as well.
QuickPrint does not have a template member function named startPrint, so specializing QuickPrint::startPrint is an error. If you repeat the template definition in QuickPrint the specializations are okay:
class QuickPrint : public Print {
template<class T>
void startPrint(void) { return; };
};
template<> // <= C2716 error given here
void QuickPrint::startPrint<Print::fontA>(void)
{
/// implementation
}
But if the goal here is to be able to call into QuickPrint polymorphically, you're in trouble, because the template function in Print can't be marked virtual.
try this:
class QuickPrint : public Print {
template<class T>
void startPrint(void) { Print::startPrint<T>(); };
};
Your issue is this line:
template<class T>
void startPrint(void) { return; };
You already provide a function body, but then try to redefine it again (using specialization), which won't work.
Remove that function body and it should work.
To define a default behaviour, provide a default value for template paramter T and then add a single specialization for that one.
Follow-up question to [Does casting to a pointer to a template instantiate that template?].
The question is just as the title says, with the rest of the question being constraints and usage examples of the class template, aswell as my tries to achieve the goal.
An important constraint: The user instantiates the template by subclassing my class template (and not through explicitly instantiating it like in my tries below). As such, it is important to me that, if possible, the user doesn't need to do any extra work. Just subclassing and it should work (the subclass actually registers itself in a dictionary already without the user doing anything other than subclassing an additional class template with CRTP and the subclass is never directly used by the user who created it). I am willing to accept answers where the user needs to do extra work however (like deriving from an additional base), if there really is no other way.
A code snippet to explain how the class template is going to be used:
// the class template in question
template<class Resource>
struct loader
{
typedef Resource res_type;
virtual res_type load(std::string const& path) const = 0;
virtual void unload(res_type const& res) const = 0;
};
template<class Resource, class Derived>
struct implement_loader
: loader<Resource>
, auto_register_in_dict<Derived>
{
};
template<class Resource>
Resource load(std::string const& path){
// error should be triggered here
check_loader_instantiated_with<Resource>();
// search through resource cache
// ...
// if not yet loaded, load from disk
// loader_dict is a mapping from strings (the file extension) to loader pointers
auto loader_dict = get_all_loaders_for<Resource>();
auto loader_it = loader_dict.find(get_extension(path))
if(loader_it != loader_dict.end())
return (*loader_it)->load(path);
// if not found, throw some exception saying that
// no loader for that specific file extension was found
}
// the above code comes from my library, the code below is from the user
struct some_loader
: the_lib::implement_loader<my_fancy_struct, some_loader>
{
// to be called during registration of the loader
static std::string extension(){ return "mfs"; }
// override the functions and load the resource
};
And now in tabular form:
User calls the_lib::load<my_fancy_struct> with a resource path
Inside the_lib::load<my_fancy_struct>, if the resource identified by the path isn't cached already, I load it from disk
The specific loader to be used in this case is created at startup time and saved in a dictionary
There is a dictionary for every resource type, and they map [file extension -> loader pointer]
If the dictionary is empty, the user either
didn't create a loader for that specific extension or
didn't create a loader for that specific resource
I only want the first case to have me throw a runtime exception
The second case should be detected at compile / link time, since it involves templates
Rationale: I'm heavily in favor of early errors and if possible I want to detect as many errors as possible before runtime, i.e. at compile and link time. Since checking if a loader for that resource exists would only involve templates, I hope it's possible to do this.
The goal in my tries: Trigger a linker error on the call to check_error<char>.
// invoke with -std=c++0x on Clang and GCC, MSVC10+ already does this implicitly
#include <type_traits>
// the second parameter is for overload resolution in the first test
// literal '0' converts to as well to 'void*' as to 'foo<T>*'
// but it converts better to 'int' than to 'long'
template<class T>
void check_error(void*, long = 0);
template<class T>
struct foo{
template<class U>
friend typename std::enable_if<
std::is_same<T,U>::value
>::type check_error(foo<T>*, int = 0){}
};
template struct foo<int>;
void test();
int main(){ test(); }
Given the above code, the following test definition does achieve the goal for MSVC, GCC 4.4.5 and GCC 4.5.1:
void test(){
check_error<int>(0, 0); // no linker error
check_error<char>(0, 0); // linker error for this call
}
However, it should not do that, as passing a null pointer does not trigger ADL. Why is ADL needed? Because the standard says so:
§7.3.1.2 [namespace.memdef] p3
[...] If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup or by qualified lookup until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). [...]
Triggering ADL through a cast, as in the following definition of test, achieves the goal on Clang 3.1 and GCC 4.4.5, but GCC 4.5.1 already links fine, as does MSVC10:
void test(){
check_error<int>((foo<int>*)0);
check_error<char>((foo<char>*)0);
}
Sadly, GCC 4.5.1 and MSVC10 have the correct behaviour here, as discussed in the linked question and specifically this answer.
The compiler instatiates a template function whenever it is referenced and a full specification of the template is available. If none is available, the compiler doesn't and hopes that some other translation unit will instantiate it. The same is true for, say, the default constructor of your base class.
File header.h:
template<class T>
class Base
{
public:
Base();
};
#ifndef OMIT_CONSTR
template<class T>
Base<T>::Base() { }
#endif
File client.cc:
#include "header.h"
class MyClass : public Base<int>
{
};
int main()
{
MyClass a;
Base<double> b;
}
File check.cc:
#define OMIT_CONSTR
#include "header.h"
void checks()
{
Base<int> a;
Base<float> b;
}
Then:
$ g++ client.cc check.cc
/tmp/cc4X95rY.o: In function `checks()':
check.cc:(.text+0x1c): undefined reference to `Base<float>::Base()'
collect2: ld returned 1 exit status
EDIT:
(trying to apply this to the concrete example)
I'll call this file "loader.h":
template<class Resource>
struct loader{
typedef Resource res_type;
virtual res_type load(std::string const& path) const = 0;
virtual void unload(res_type const& res) const = 0;
loader();
};
template<class Resource>
class check_loader_instantiated_with : public loader<Resource> {
virtual Resource load(std::string const& path) const { throw 42; }
virtual void unload(Resource const& res) const { }
};
template<class Resource>
Resource load(std::string const& path){
// error should be triggered here
check_loader_instantiated_with<Resource> checker;
// ...
}
And another file, "loader_impl.h":
#include "loader.h"
template<class Resource>
loader<Resource>::loader() { }
This solution has one weak point that I know of. Each compilation unit has a choice of including either only loader.h or loader_impl.h. You can only define loaders in compilation units that include loader_impl, and in those compilation units, the error checking is disabled for all loaders.
After thinking a bit about your problem, I don't see any way to achieve this. You need a way to make the instantiation "export" something outside the template so that it can be accessed without referencing the instantiation. A friend function with ADL was a good idea, but unfortunately it was shown that for ADL to work, the template had to be instantiated. I tried to find another way to "export" something from the template, but failed to find one.
The usual solution to your problem is to have the user specializes a trait class:
template < typename Resource >
struct has_loader : boost::mpl::false_ {};
template <>
struct has_loader< my_fancy_struct > : boost::mpl::true_ {};
To hide this from the user, you could provide a macro:
#define LOADER( loaderName, resource ) \
template <> struct has_loader< resource > : boost::mpl::true_ {}; \
class loaderName \
: the_lib::loader< resource > \
, the_lib::auto_register_in_dict< loaderName >
LOADER( some_loader, my_fancy_struct )
{
public:
my_fancy_struct load( std::string const & path );
};
It is up to you to determine whether having this macro is acceptable or not.
template <class T>
class Wrapper {};
void CheckError(Wrapper<int> w);
template <class T>
class GenericCheckError
{
public:
GenericCheckError()
{
Wrapper<T> w;
CheckError(w);
}
};
int main()
{
GenericCheckError<int> g1; // this compiles fine
GenericCheckError<char> g2; // this causes a compiler error because Wrapper<char> != Wrapper<int>
return 0;
}
Edit:
Alright this is as close as I can get. If they subclass and either instantiate OR define a constructor that calls the parent's constructor, they will get a compiler error with the wrong type. Or if the child class is templatized and they subclass and instantiate with the wrong type, they will get a compiler error.
template <class T> class Wrapper {};
void CheckError(Wrapper<int> w) {}
template <class T>
class LimitedTemplateClass
{
public:
LimitedTemplateClass()
{
Wrapper<T> w;
CheckError(w);
}
};
// this causes no compiler error
class UserClass : LimitedTemplateClass<int>
{
UserClass() : LimitedTemplateClass<int>() {}
};
// this alone (no instantiation) causes a compiler error
class UserClass2 : LimitedTemplateClass<char>
{
UserClass2() : LimitedTemplateClass<char>() {}
};
// this causes no compiler error (until instantiation with wrong type)
template <class T>
class UserClass3 : LimitedTemplateClass<T>
{
};
int main()
{
UserClass u1; // this is fine
UserClass2 u2; // this obviously won't work because this one errors after subclass declaration
UserClass3<int> u3; // this is fine as it has the right type
UserClass3<char> u4; // this one throws a compiler error
return 0;
}
Obviously you can add other accepted types by defining additional CheckError functions with those types.