Eliminate 'constructor with 1 argument is not explicit' cppcheck warning
authorIvan Maidanski <ivmai@mail.ru>
Wed, 14 Sep 2016 22:03:15 +0000 (01:03 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Wed, 14 Sep 2016 22:04:49 +0000 (01:04 +0300)
Note that -D CPPCHECK should be passed to cppcheck to activate
this workaround.

* include/gc_allocator.h (GC_ATTR_EXPLICIT): New macro (defined to
"explicit" keyword if at least C++11 or CPPCHECK, otherwise to empty).
* include/gc_allocator.h (gc_allocator::gc_allocator,
gc_allocator_ignore_off_page::gc_allocator_ignore_off_page,
traceable_allocator::traceable_allocator): Use GC_ATTR_EXPLICIT.
* tests/test_cpp.cc (A::A, B::B, C::C, D::D): Likewise.
* tests/test_cpp.cc (GC_ATTR_EXPLICIT): Define macro (as empty) unless
already defined in included gc_allocator.h.

include/gc_allocator.h
tests/test_cpp.cc

index 367cfe2..3ea80a0 100644 (file)
 #  define GC_ATTR_UNUSED
 #endif
 
+#ifndef GC_ATTR_EXPLICIT
+# if (__cplusplus >= 201103L) || defined(CPPCHECK)
+#   define GC_ATTR_EXPLICIT explicit
+# else
+#   define GC_ATTR_EXPLICIT /* empty */
+# endif
+#endif
+
 /* First some helpers to allow us to dispatch on whether or not a type
  * is known to be pointer-free.
  * These are private, except that the client may invoke the
@@ -116,7 +124,8 @@ public:
     gc_allocator(const gc_allocator&) throw() {}
 # if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
   // MSVC++ 6.0 do not support member templates
-  template <class GC_Tp1> gc_allocator(const gc_allocator<GC_Tp1>&) throw() {}
+  template <class GC_Tp1> GC_ATTR_EXPLICIT
+    gc_allocator(const gc_allocator<GC_Tp1>&) throw() {}
 # endif
   ~gc_allocator() throw() {}
 
@@ -191,7 +200,7 @@ public:
     gc_allocator_ignore_off_page(const gc_allocator_ignore_off_page&) throw() {}
 # if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
   // MSVC++ 6.0 do not support member templates
-  template <class GC_Tp1>
+  template <class GC_Tp1> GC_ATTR_EXPLICIT
     gc_allocator_ignore_off_page(const gc_allocator_ignore_off_page<GC_Tp1>&)
         throw() {}
 # endif
@@ -271,8 +280,8 @@ public:
     traceable_allocator(const traceable_allocator&) throw() {}
 # if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
   // MSVC++ 6.0 do not support member templates
-  template <class GC_Tp1> traceable_allocator
-          (const traceable_allocator<GC_Tp1>&) throw() {}
+  template <class GC_Tp1> GC_ATTR_EXPLICIT
+    traceable_allocator(const traceable_allocator<GC_Tp1>&) throw() {}
 # endif
   ~traceable_allocator() throw() {}
 
index d9ebd28..642bdfd 100644 (file)
@@ -76,10 +76,14 @@ extern "C" {
 # define ATTR_UNUSED /* empty */
 #endif
 
+#ifndef GC_ATTR_EXPLICIT
+# define GC_ATTR_EXPLICIT /* empty */
+#endif
+
 class A {public:
     /* An uncollectible class. */
 
-    A( int iArg ): i( iArg ) {}
+    GC_ATTR_EXPLICIT A( int iArg ): i( iArg ) {}
     void Test( int iArg ) {
         my_assert( i == iArg );}
     int i;};
@@ -88,7 +92,7 @@ class A {public:
 class B: public GC_NS_QUALIFY(gc), public A { public:
     /* A collectible class. */
 
-    B( int j ): A( j ) {}
+    GC_ATTR_EXPLICIT B( int j ): A( j ) {}
     ~B() {
         my_assert( deleting );}
     static void Deleting( int on ) {
@@ -101,7 +105,7 @@ int B::deleting = 0;
 class C: public GC_NS_QUALIFY(gc_cleanup), public A { public:
     /* A collectible class with cleanup and virtual multiple inheritance. */
 
-    C( int levelArg ): A( levelArg ), level( levelArg ) {
+    GC_ATTR_EXPLICIT C( int levelArg ): A( levelArg ), level( levelArg ) {
         nAllocated++;
         if (level > 0) {
             left = new C( level - 1 );
@@ -133,7 +137,7 @@ class D: public GC_NS_QUALIFY(gc) { public:
     /* A collectible class with a static member function to be used as
     an explicit clean-up function supplied to ::new. */
 
-    D( int iArg ): i( iArg ) {
+    GC_ATTR_EXPLICIT D( int iArg ): i( iArg ) {
         nAllocated++;}
     static void CleanUp( void* obj, void* data ) {
         D* self = static_cast<D*>(obj);