I have following snippet
#include <type_traits>
#include <boost/type_traits.hpp>
class C { C() { } };
int main()
{
static_assert(!boost::has_trivial_default_constructor<C>::value, "Constructible");
static_assert(!std::is_default_constructible<C>::value, "Constructible");
}
Conditions are not equal, but first condition works fine and second construction give error, that constructor is private. Compiler gcc 4.7... So, is this gcc bug, or it's defined by standard?
http://liveworkspace.org/code/NDQyMD$5
OK. Since this conditions are really unequal - we can use something like this
#include <type_traits>
#include <boost/type_traits.hpp>
class C { private: C() noexcept(false) { } };
int main()
{
static_assert(!boost::has_nothrow_constructor<C>::value, "Constructible");
static_assert(!std::is_nothrow_constructible<C>::value, "Constructible");
}
http://liveworkspace.org/code/NDQyMD$24
Anyway, i know, that static_assert should not fails, since types are really not default constructible/not nothrow constructible. Question is: WHY there is compilation error, not by my static assert?
Looks like a compiler bug. Let's see the following example of SFINAE(similar implementation is used in g++'s type_traits header)
#include <type_traits>
class Private
{
Private()
{
}
};
class Delete
{
Delete() = delete;
};
struct is_default_constructible_impl
{
template<typename T, typename = decltype(T())>
static std::true_type test(int);
template<typename>
static std::false_type test(...);
};
template <class T>
struct is_default_constructible: decltype(is_default_constructible_impl::test<T>(0))
{
};
int main()
{
static_assert(is_default_constructible<Private>::value, "Private is not constructible");
static_assert(is_default_constructible<Delete>::value, "Delete is not constructible");
}
The second assert works as expected, we can't deduce Delete type, since the class has only one deleted constructor. But when compiler tries to deduce type of Private(), it gives error: Private::Private() is private. So, we have two classes with private constructor, but one of them gives error, and second - not. I think, that this behavior is wrong, but I can't find confirmation in the standard.
P.S. all off presented codes compiles by clang without any errors.
Related
I am having a problem with the changes that were made to the way C++ templates are compiled, between the C++17 and 19 standards. Code that used to compile in VS2017 throws a compiler error since I upgraded to VS2019 or VS2022.
Situations have to do with the fact that the compiler now runs a basic syntax check on the template definition when it sees this definition ("first pass") and not only when the template is actually used.
Code example 1:
class Finder
{
template<typename T>
T convert_to(HANDLE h)
{
return Converters::Converter<T>::Convert(get_data(h));
}
};
Here, the template class Converter<> resides in namespace Converters, and get_data is a member function of Finder which returns something that can be passed into the Convert function.
Since we're dealing with templates, this code sits in a header file "Finder.h". The header file doesn't #include "Converters.h". Finder.h is shared across several projects, some of which don't even know the Converters.h file namespace.
As long as no code calls the MyClass::convert_to<> function, this compiles in VS2017, but not so in VS2019 and VS2022:
error C3861: 'Converters': identifier not found
The obvious solution is, of course, to #include "Converters.h" either in this header file, or in the precompiled headers file. However, as was said, Converters.h is not known in all places which use MyClass. Another solution would be to use archaic #define CONVERTERS_H in the Converters.h header and enclose the function definition in #ifdef CONVERTERS_H, but this looks really ugly.
My question is: Is there a way to prevent the compiler from doing this "first pass"? Or to re-write this code so that it compiles? I don't mind if it's MS specific; no other compiler will ever see the code.
Code example 2:
class MyClass2
{
template<class T>
static void DoSomething(T* ptr) { static_assert(false, "Don't do this"); }
// lots more member functions, most of them 'static'
};
template<> void MyClass::DoSomething(CWnd* ptr) { /*some useful code*/ }
/// and some more specializations of DoSomething
The intention is that the static_assert should emit an error message whenever DoSomething is called with an argument for which no explicit specialization of this template function is defined. This worked in VS2017, but in VS2022, the "first pass" of the compiler triggers the static_assert.
Again, I wonder how I could achieve this effect, other than by replacing the static_assert by a run-time assertion.
Or am I thinking into a completely wrong direction?
Thanks
Hans
The first case requires a forward declaration of some kind, that's unavoidable.
The second case, though, can be handled with just a minor change.
#include <type_traits>
class CWnd {};
class MyClass2
{
public:
template<class T, class Y=T>
static void DoSomething(T* ptr) { static_assert(!std::is_same_v<Y,T>, "Don't do this"); }
};
template<> void MyClass2::DoSomething(CWnd* ptr) { /*some useful code*/ }
void foo()
{
int a;
CWnd b;
MyClass2::DoSomething(&a); // ERROR
MyClass2::DoSomething(&b); // OK
}
(partial answer)
To fix MyClass2, the usual trick is to make false depend on T, so that the first pass does not trigger the assert.
// dependent false
template <typename>
constexpr bool dep_false() { return false; }
class MyClass2
{
template<class T>
static void DoSomething(T* ptr) {
static_assert(dep_false<T>(), "Don't do this");
}
// lots more member functions, most of them 'static'
};
// specialization example
template<>
void MyClass2::DoSomething<int>(int* ptr) {
std::cout << "int* is OK\n";
}
I must have missed something in C++ specification because I can't explain why the following code compiles successfully:
class MyClass { static void fun(); };
int main() { MyClass::MyClass::MyClass::fun(); }
Could somebody point me to the standard or just explain me the semantics? I would guess that only one MyClass:: is allowed. Two MyClass::MyClass:: should cause error. Experimenting with MS Visual C++ 2017 and GNU C++ 6.2.0 I realized that any count of MyClass:: is allowed.
It is not only a theoretical question. I wanted to use SFINAE and condition compilation with existence of a sub-class. Worked good until the base class has the same name as the sub-class:
template <class T> void callWorkout() { T::SubClass::workout(); }
struct X { struct SubClass { static void workout(); }; };
struct Y { /*empty*/ };
struct SubClass { static void workout(); };
int main() {
callWorkout<X>(); // works fine - compiled
callWorkout<Y>(); // works "fine" - not compiled, no SubClass in Y
callWorkout<SubClass>(); // ooops? - still compiled, there is no 'SubClass' in SubClass
}
My question has two parts:
What is the exact semantics of MyClass::MyClass::?
How can I fix the above example not to compile callWorkout<SubClass>()? (I tried to add sizeof(typename T::SubClass) but surprisingly it compiles also for T=SubClass)
That's the injected class name of MyClass. And you can verify it's not T by simply using std::is_same_v<T, typename T::SubClass> in a SFINAE conditional.
template <class T>
auto callWorkout() -> std::enable_if_t<!std::is_same_v<T, typename T::SubClass>>
{ T::SubClass::workout(); }
If you don't need SFINAE (because you aren't trying to control overload resolution), then a static_assert with a descriptive custom message can also do nicely.
I was trying to integrate the boost::share_ptr into a pair of templated classes that were originally derived from a boost::asio example I found. When I define a type within one class which is a shared::ptr of that class. I can't seem to reference the type in another templated class. If I remove templates from the code, it all compiles.
This won't compile:
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
using namespace std;
template <typename TSomething1>
class SomeTemplateT : public boost::enable_shared_from_this<SomeTemplateT<TSomething1> >
{
public:
typedef boost::shared_ptr<SomeTemplateT<TSomething1> > Ptr;
static Ptr Create()
{
return Ptr(new SomeTemplateT<TSomething1>());
}
SomeTemplateT()
{
cout << "SomeTemplateT created" << endl;
}
};
template <typename TSomething>
class OtherTemplateT
{
public:
OtherTemplateT()
{
// COMPILATION ERROR HERE
SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();
}
private:
};
The code above yields the following compilation error:
src\Templates\main.cpp: In constructor 'OtherTemplateT<TSomething>::OtherTemplateT()':
src\comps\oamp\src\Templates\main.cpp:30: error: expected ';' before 'someTemplate'
Taking virtually the same code without templates compiles without difficulty:
class SomeTemplateT : public boost::enable_shared_from_this<SomeTemplateT>
{
public:
typedef boost::shared_ptr<SomeTemplateT> Ptr;
static Ptr Create()
{
return Ptr(new SomeTemplateT());
}
SomeTemplateT()
{
cout << "SomeTemplateT created" << endl;
}
};
class OtherTemplateT
{
public:
OtherTemplateT()
{
SomeTemplateT::Ptr someTemplate = SomeTemplateT::Create();
}
private:
};
Platform information:
I'm using gcc4.4.0 from MinGW on windows XP (Code:Blocks IDE).
Am I doing something wrong?
EDIT:
I forgot to mention that if I replace the use of the Ptr typedef with the full declaration of the shared ptr:
boost::shared_ptr
Everything compiles fine.
Also, I can use the type in code outside the of the template.
SomeTemplateT<TSomething>::Ptr is a dependent name; that is, its definition depends on the template parameter. The compiler can't assume that it's a type name unless you say so:
typename SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();
^^^^^^^^
You need to use typename:
typename SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();
This is required to make parsing possible without semantic analysis. Whether SomeTemplateT<TSomething>::Ptr is a type or a member is not known until SomeTemplateT<TSomething> has been compiled.
A example taken from the C++11 Standard (n3290) that demonstrate why the keyword typename (in this context) is useful.
( 14.6 Name resolution [temp.res] )
struct A
{
struct X { };
int X;
};
struct B
{
struct X { };
};
template<class T> void f(T t)
{
typename T::X x;
}
void foo()
{
A a;
B b;
f(b); // OK: T::X refers to B::X
f(a); // error: T::X refers to the data member A::X not the struct A::X
}
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.
template<typename T> struct A {
auto func() -> decltype(T::func()) {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
Seems pretty simple to me. But MSVC fails to compile.
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'func' : is not a member of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see declaration of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see reference to class template instantiation 'A<T>' being compiled
with
[
T=B
]
visual studio 2010\projects\temp\temp\main.cpp(4): error C3861: 'func': identifier not found
Even though the compiler will happily accept calling the function. The below sample compiles fine.
template<typename T> struct A {
void func() {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
I've got the same issue trying to use any types from the template argument.
template<typename T> struct A {
typedef typename T::something something;
};
class B : public A<B> {
typedef char something;
};
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'something' : is not a member of 'B'
Whereas class B clearly defines a type called "something". The compiler is perfectly happy to call functions on an object of type T, T& or T*, but I can't seem to access any types from T.
You are trying to use T::func before it was declared. That's why the compiler shouts at you. Notice that when you derive from a class, the class is generated if it comes from a class template. And the implicit generation of the class (which is called implicit instantiation) necessiates the generation of declarations for all its members (so the compiler knows the sizeof value of the class, and can perform lookup into it).
So it also instantiates the declaration auto func() -> decltype(T::func()) and surely fails here.
There seem to be several issues with your code, one of which looks like a VS10 bug.
You're calling T::func() from A without casting A to T, this is needed as part of CRTP since A doesn't derive from T. -- FixL return static_cast<T*>(this)->func();
What you're passing to decltype looks like a static function invocation while func is in fact an instance function. Since decltype doesn't actually run the function you should do something like this decltype(static_cast<T*>(nullptr)->func())
func is private in B and can't be called from A -- Fix: change A to be a struct
This looks like a bug in VS10, even after all these fixes I get an error that you're trying to use an undefined class B in the decltype.
As a workaround can you refactor func out into a base class? (now we need two template parameters, one for casting to and one for decltype thus creating a new idiom CRTPEX)
struct Base {
void func() { }
};
template<typename T, typename U> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<U*>(this)->func();
}
};
struct B : public A<Base, B>, public Base {
};
I see that g++ also chokes on this decltype can anyone confirm that this is a defect? If so I will open a bug for Microsoft. It is my understanding that the following code is valid but neither g++ nor VC10 compile it.
template<typename T> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<T*>(this)->func();
}
};
struct B : public A<B> {
void func() {}
};
First, I think that the close-to-proper code is:
template<typename T> struct A {
auto func()
-> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
As Motti pointed out. However that still fails, and I think for the reason that the return type of the base has to be known when B is declated to inherit from A<B>, but since B is not defined yet, it becomes a chicken and egg problem.
However, it may be finally be possible in C++1y by using simply auto (without decltype), I tried with gcc-4.8.2
template<typename T> struct A {
auto func()
//c++1y// -> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
This compiles (c++ -std=c++1y) and runs:
int main(){
B b; b.func();
}
Two disclaimers: I don't know why this works. I don't know how standard it is.