I am trying to get a simple example to work to understand how to use std::enable_if, here is the problem:
I am reading the textbook C++ Templates The Complete Guide by David Vandevoorde, Nicolai M.Josuttis, Chapter 6, Section 5.
This chapter mentions: "std::enable_if to prevent being able to copy objects of a class template C<> if the template parameter is an integral type", and its following code:
template <typename T> class C {
public:
// user-define the predefined copy constructor as deleted (with conversion to
// volatile to enable better matches)
C(C const volatile &) = delete;
// if T is not integral type, provide copy constructor template with better match:
template <typename U,
typename = std::enable_if_t<!std::is_integral<U>::value>>
C(C<U> const &) {
std::cout << "tmpl copy constructor" << std::endl;
}
};
My question is, how should the above code be called and used?
for example, I tried:
C<int> c_int;
std::string s = "sname";
C<std::string> c_string1(std::string);
C<std::string> c_string2(c_string1);
But give me compile error:
specialmember3.cc:22:39: error: no matching function for call to ‘C<std::__cxx11::basic_string<char> >::C(C<std::__cxx11::basic_string<char> > (&)(std::string))’
22 | C<std::string> c_string2(c_string1);
| ^
specialmember3.cc:14:3: note: candidate: ‘template<class U, class> C<T>::C(const C<U>&)’
14 | C(C<U> const &) {
| ^
specialmember3.cc:14:3: note: template argument deduction/substitution failed:
specialmember3.cc:22:39: note: mismatched types ‘const C<U>’ and ‘C<std::__cxx11::basic_string<char> >(std::string)’ {aka ‘C<std::__cxx11::basic_string<char> >(std::__cxx11::basic_string<char>)’}
22 | C<std::string> c_string2(c_string1);
| ^
specialmember3.cc:9:3: note: candidate: ‘constexpr C<T>::C() [with T = std::__cxx11::basic_string<char>]’
9 | C() = default;
| ^
specialmember3.cc:9:3: note: candidate expects 0 arguments, 1 provided
Can someone please give me some hints or code guidance on how to use above template constructor?
You have declared c_string1 as a function. I think you meant this
C<std::string> c_string1;
C<std::string> c_string2(c_string1);
That class, as it is defined, is somewhat useless.
a) You can't default-initialize it, default constructor is removed. C<int> c_int; is ill-formed.
b) You can't create it from value, e.g. C<std::string> c_string1(some_str);, because that constructor does not exist.
Essentially you can copy it, but you cannot create it, which is a nonsense. It breaks rule of 3/5/0.
template <typename T>
class C {
public:
C() /*Initialization here */ {}
C(const T& val) /*Initialization here */ {
std::cout << "tmpl copy constructor: " << val << std::endl;
}
// user-define the predefined copy constructor as deleted (with conversion to
// volatile to enable better matches)
C(C const volatile &) = delete;
// if T is not integral type, provide copy constructor template with better match:
template <typename U,
typename = std::enable_if_t<!std::is_integral<U>::value>>
C(C<U> const &) {
std::cout << "tmpl copy constructor" << std::endl;
}
};
In that case those would be legal:
C<int> c_int;
std::string s = "sname";
C<std::string> c_string1(s);
C<std::string> c_string2(c_string1);
THe copy template defined disallows copying of C if T is integral, so
C<int> c_int2 (c_int); // use of deleted function 'C<T>::C(const volatile C<T>&)
Related
I'm attempting to create a base class for creating helpers around various scoped operations, and to do so the base class allows the assignment of a callable. A simple predicate determines whether or not the callable is invoked. Regardless, the dtor is always invoked.
The catch is that each derived class needs to explicitly inherit the operator=. Is there a way to write the base class so that this is not required?
#include <functional>
#include <iostream>
using callback_t = std::function<void(void)>;
struct C
{
constexpr C(bool ok) : ok_{ok} {}
bool ok_ {false};
bool operator=(callback_t fn) const noexcept {
return ok_ ? fn(), true : false;
}
~C() noexcept {
std::cout << "end\n";
}
};
struct D final : public C
{
using C::operator=;
};
int main()
{
auto predicate = [] { return true; };
D{predicate()} = [] {
std::cout << "ok\n";
};
D{false} = [] {
std::cout << "wrong\n";
};
}
(also https://gcc.godbolt.org/z/eh8ncffos)
Removing the line from struct D
using C::operator=;
causes compile errors since Ds default copy-operator preempts C's custom operator=.
<source>: In function 'int main()':
<source>:24:9: error: no match for 'operator=' (operand types are 'D' and 'main()::<lambda()>')
24 | };
| ^
<source>:14:12: note: candidate: 'constexpr D& D::operator=(const D&)'
14 | struct D final : public C
| ^
<source>:14:12: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'const D&'
<source>:14:12: note: candidate: 'constexpr D& D::operator=(D&&)'
<source>:14:12: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'D&&'
<source>:27:9: error: no match for 'operator=' (operand types are 'D' and 'main()::<lambda()>')
27 | };
| ^
<source>:14:12: note: candidate: 'constexpr D& D::operator=(const D&)'
14 | struct D final : public C
| ^
<source>:14:12: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'const D&'
<source>:14:12: note: candidate: 'constexpr D& D::operator=(D&&)'
<source>:14:12: note: no known conversion for argument 1 from 'main()::<lambda()>' to 'D&&'
The catch is that each derived class needs to explicitly inherit the operator=. Is there a way to write the base class so that this is not required?
No, this isn't possible.
The rule is that functions in different scopes do not overload. Since the derived class will always have something named operator= (either the derived class declares one itself, or the copy assignment operator is declared implicitly... even if it would be defined as deleted). So when you do derived = x;, name lookup for operator= will start in Derived and, having found candidates, stop there. It won't keep going to look into the base class... unless you bring in that candidate with a using-declaration like you demonstrated the question.
The only way to still use operator= but stash the functionality somewhere would be to actually invert your class hierarchy. Instead of:
struct C {
// ... implementation here ...
};
struct D : C {
using C::operator=;
};
// use D
you can do:
template <typename Derived>
struct C {
// implementation here
};
struct D { }
// use C<D>
This way, C is actually the class you're interacting with, so its operator= would be the first candidate considered.
Alternatively, if you simply don't use = as the spelling for this operation, every other operator is available and they would not need a using-declaration in the derived class to work.
Given the comment about wishing to avoid parentheses, your list of binary operators that would not require one are: ->*, +, -, *, /, %, ^, &, |, &&, ||, <, >, <<, and >> (plus the compound-assignment versions of those).
I'm deliberately excluding == and <=> from the list because those are special and just don't.
I'm trying to make a movable wrapper to non-copyable, non-movable class, however I have a problem passing a const std::string variable to the constructor. The minimal example below produces following error:
#include <iostream>
#include <memory>
#include <string>
#include <utility>
struct X {
std::string x;
X(const std::string &x) : x(x) {}
X(const X &x) = delete;
X(X &&x) = delete;
};
struct Wrapper {
std::unique_ptr<X> x;
Wrapper(const Wrapper & wrapper) = delete;
Wrapper(Wrapper && wrapper) = default;
template<typename... Args>
Wrapper(Args&&... args) : x(std::make_unique<X>(std::forward(args)...)) {}
};
int main() {
const std::string XXX = "XXX";
Wrapper w{XXX};
std::cout << w.x->x << std::endl;
}
Error message here:
forwarding.cc:21:53: error: no matching function for call to 'forward'
Wrapper(Args&&... args) : x(std::make_unique<X>(std::forward(args)...)) {}
^~~~~~~~~~~~
forwarding.cc:26:13: note: in instantiation of function template specialization 'Wrapper::Wrapper<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > &>' requested here
Wrapper w{XXX};
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/move.h:73:5: note: candidate template ignored: couldn't infer template argument '_Tp'
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/move.h:84:5: note: candidate template ignored: couldn't infer template argument '_Tp'
forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
^
1 error generated.
You need to explicitly pass template parameters to std::forward:
std::forward<Args>(args)...
This is because std::forward needs some way of knowing the "original value category" of args..., which is impossible through template argument deduction alone as args is always an lvalue.
Lvalues will deduced as lvalue references in the context of template argument deduction for forwarding references (as a special rule), so std::forward can do its job by looking at the types inside Args....
I'm trying to build up some code that wants to declare a local variable (say of type test, as shown below). Construction of that local variable should use a constructor that takes a special Tag argument if such a constructor exists, or the default constructor otherwise.
What we've been able to come up with is as follows, where we specialize to construct either a void argument or a Tag argument, but compilers don't like that:
#include <iostream>
using std::cout;
struct Tag { };
template <bool z>
struct helper {
using type = void;
};
template <>
struct helper<true> {
using type = Tag;
};
template <bool z>
static typename helper<z>::type get_arg() {
return typename helper<z>::type();
}
struct test {
test(void) { cout << "test(void)\n"; }
test(Tag x) { cout << "test(Tag)\n"; }
test(const test&) = delete;
test(test&&) = delete;
};
template <typename T>
void try_construct() {
// we would be selecting from one of these by template metaprogramming
T a{typename helper<false>::type()};
T b{typename helper<true>::type()};
T c{get_arg<false>()};
T d{get_arg<true>()};
// Then do stuff with the suitably-constructed instance of T
// . . .
}
int main(void) {
try_construct<test>();
return 0;
}
Compiler output:
$ g++ -std=c++11 -c foo.cpp
foo.cpp: In instantiation of 'void try_construct() [with T = test]':
foo.cpp:38:23: required from here
foo.cpp:30:37: error: no matching function for call to 'test::test(<brace-enclosed initializer list>)'
T a{typename helper<false>::type()};
^
foo.cpp:30:37: note: candidates are:
foo.cpp:22:3: note: test::test(Tag)
test(Tag x) { cout << "test(Tag)\n"; }
^
foo.cpp:22:3: note: no known conversion for argument 1 from 'void' to 'Tag'
foo.cpp:21:3: note: test::test()
test(void) { cout << "test(void)\n"; }
^
foo.cpp:21:3: note: candidate expects 0 arguments, 1 provided
foo.cpp:33:23: error: no matching function for call to 'test::test(<brace-enclosed initializer list>)'
T c{get_arg<false>()};
^
foo.cpp:33:23: note: candidates are:
foo.cpp:22:3: note: test::test(Tag)
test(Tag x) { cout << "test(Tag)\n"; }
^
foo.cpp:22:3: note: no known conversion for argument 1 from 'helper<false>::type {aka void}' to 'Tag'
foo.cpp:21:3: note: test::test()
test(void) { cout << "test(void)\n"; }
^
foo.cpp:21:3: note: candidate expects 0 arguments, 1 provided
We know how to test on the presence of the constructor, so I've left that our of the example. If that does end up being relevant in a solution taking a different approach, feel free to go that route.
Our ultimate goal is to require one of the default constructor or the Tag constructor, and neither of the copy or move constructors.
namespace details {
template<class T>
T maybe_tag_construct(std::true_type) {
return T(Tag{});
}
template<class T>
T maybe_tag_construct(std::false_type) {
return T();
}
}
template<class T>
T maybe_tag_construct() {
return details::maybe_tag_construct<T>( std::is_constructible<T, Tag>{} );
}
now auto t =maybe_tag_construct<test>(); constructs test from Tag iff it works.
It also does elided move construction before c++17, and in c++17 no move construction occurs.
In order to pass an instance of void around, you need the "regular void" proposal, which is on track for c++2a last I checked.
I think something along these lines works:
#include <type_traits>
template <typename T, bool B = std::is_constructible<Tag, T>> struct H;
template <typename T>
struct H<T, false> {
T t;
H() : t() {}
};
template <typename T>
struct H<T, true> {
T t;
H() : t(Tag) {}
};
try_construct() {
H<T> h;
h.t;
}
Given the following source code:
#include <memory>
#include <iostream>
using namespace std;
struct concept
{
virtual void perform() = 0;
};
struct model : concept, enable_shared_from_this<model>
{
void perform() override {
cout << "my pointer is " << shared_from_this().get() << endl;
}
};
int main(int argc, const char * argv[])
{
// shared_ptr<concept> concept_ptr = make_shared<model>();
shared_ptr<concept> concept_ptr { new model };
concept_ptr->perform();
return 0;
}
Compiling under gcc, this code compiles and associates the internal weak_ptr with the address of model.
Under clang the code will not compile (error message included at the end)
If you replace the initialisation of concept_ptr with shared_ptr<concept> concept_ptr = make_shared<model>(); it will compile on both.
Which is correct?
edit:
My version of clang is the one that ships with Xcode:
$ clang --version
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.3.0
Thread model: posix
edit2:
Just wanted to say thanks to everyone for contributing.
If you're interested, the reason I want to do this is that I want an opaque interface to an implementation with shared-handle semantics. Some implementations (async ones) require that callback objects ensure that the implementation object still exists (argues for shared_from_this and weak_ptr::lock). Other implementations do not require this. I wanted to avoid encumbering the concept (public interface) with the enable_shared_from_this<> base class, since that couples implementation with interface - a known evil.
In most cases, it's reasonable to use make_shared to create the implementation object. In rarer cases that require a custom destructor, the following seems portable:
auto concept_ptr = static_pointer_cast<concept>(shared_ptr<model> {
new model ,
[](model* self) {
// some_deletion_operation on self;
} });
appendix:
error message on clang:
In file included from /Users/richardh/Documents/dev/Scratchpad/tryit/tryit/try2.cpp:1:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:4013:35: error: no viable overloaded '='
__e->__weak_this_ = *this;
~~~~~~~~~~~~~~~~~ ^ ~~~~~
...etc...
I understand that libstdc++ follows the standard more closely here.
Concerning the requirements for
shared_ptr<T> shared_from_this();
shared_ptr<const T> shared_from_this() const;
both N3337 §20.7.2.4 (7) and N3936 §20.8.2.5 (7) only require
enable_shared_from_this<T> shall be an accessible base class
of T. *this shall be a subobject of an object t of type T. There shall
be at least one shared_ptr instance p that owns &t.
There is no requirement named that one shared_ptr owning &t actually has to be a shared_ptr<T> or shared_ptr<A_to_T_Convertible>.
And that very function is the core of that class' functionality.
Thus, given Tp as the actual param of the enabled_shared_from_this and Tp1 as the actual parameter of that owning shared_ptr, is_convertible<Tp1, Tp>::value == true, let alone is_same<Tp1, Tp>::value == true, is not required by the standard, same for respective pointers.
And indeed, the full output of clang++ using libc++ has
/usr/local/bin/../include/c++/v1/memory:3997:35: error: no viable overloaded '='
__e->__weak_this_ = *this;
~~~~~~~~~~~~~~~~~ ^ ~~~~~
/usr/local/bin/../include/c++/v1/memory:4035:5: note: in instantiation of
function template specialization
'std::__1::shared_ptr<concept>::__enable_weak_this<model>' requested here
__enable_weak_this(__p);
^
[...]enable_shared.cxx:34:25: note: in instantiation
of function template specialization
'std::__1::shared_ptr<concept>::shared_ptr<model>' requested here
shared_ptr<concept> model_ptr1(new model);
^
/usr/local/bin/../include/c++/v1/memory:4942:15: note: candidate function not
viable: no known conversion from 'std::__1::shared_ptr<concept>' to 'const
std::__1::weak_ptr<model>' for 1st argument
weak_ptr& operator=(weak_ptr const& __r) _NOEXCEPT;
^
/usr/local/bin/../include/c++/v1/memory:4953:15: note: candidate function not
viable: no known conversion from 'std::__1::shared_ptr<concept>' to
'std::__1::weak_ptr<model>' for 1st argument
weak_ptr& operator=(weak_ptr&& __r) _NOEXCEPT;
^
/usr/local/bin/../include/c++/v1/memory:4949:9: note: candidate template
ignored: could not match 'weak_ptr' against 'shared_ptr'
operator=(weak_ptr<_Yp> const& __r) _NOEXCEPT;
^
/usr/local/bin/../include/c++/v1/memory:4960:9: note: candidate template
ignored: could not match 'weak_ptr' against 'shared_ptr'
operator=(weak_ptr<_Yp>&& __r) _NOEXCEPT;
^
/usr/local/bin/../include/c++/v1/memory:4967:13: note: candidate template
ignored: disabled by 'enable_if' [with _Yp = concept]
is_convertible<_Yp*, element_type*>::value,
^
So libc++ here wants
is_convertible<Tp1* /*= Base* = concept**/, Tp* /*= Derived* = model* */>
which of course fails here, that the run-time *this of that very shared_ptr<Tp1> would be dynamic_cast-able to Tp* is out of ansatz here.
From this perspective, it's also clear why shared_ptr<concept> concept_ptr = make_shared<model>(); doesn't suffer from that; on the rhs there is a shared_ptr<Tp /* = derived = model */> constructor and for that ptr is_convertible holds.
libstdc++ doesn't suffer from this, because it passes the argument, thus its type (= Derived = model), of the shared_ptr<Tp1 /* = Base = concept*/> constructor down to the internal weak_ptr<T /*= Derived = model*/> assignment, not the shared_ptr in construction.
https://github.com/mirrors/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L848
template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr
{
https://github.com/mirrors/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L858
template<typename _Tp1>
explicit __shared_ptr(_Tp1* __p)
: _M_ptr(__p), _M_refcount(__p)
{
__glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
static_assert( !is_void<_Tp1>::value, "incomplete type" );
static_assert( sizeof(_Tp1) > 0, "incomplete type" );
__enable_shared_from_this_helper(_M_refcount, __p, __p);
}
https://github.com/mirrors/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L1459
template<typename _Tp, _Lock_policy _Lp>
class __enable_shared_from_this
{
https://github.com/mirrors/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L1482
private:
template<typename _Tp1>
void
_M_weak_assign(_Tp1* __p, const __shared_count<_Lp>& __n) const noexcept
{ _M_weak_this._M_assign(__p, __n); }
template<typename _Tp1>
friend void
__enable_shared_from_this_helper(const __shared_count<_Lp>& __pn,
const __enable_shared_from_this* __pe,
const _Tp1* __px) noexcept
{
if (__pe != 0)
__pe->_M_weak_assign(const_cast<_Tp1*>(__px), __pn);
}
My point of view only; comments welcome.
#Richard Hodges: +1, very interesting topic
The following won't compile:
struct S {
template <class T> S(T) {}
};
void f(int) {}
int main() {
S(f);
}
g++-4.9 says
template.cpp: In function ‘int main()’:
template.cpp:6:8: error: no matching function for call to ‘S::S()’
S(f);
^
template.cpp:6:8: note: candidates are:
template.cpp:2:24: note: template<class T> S::S(T)
template <class T> S(T) {}
^
template.cpp:2:24: note: template argument deduction/substitution failed:
template.cpp:6:8: note: candidate expects 1 argument, 0 provided
S(f);
^
template.cpp:1:8: note: constexpr S::S(const S&)
struct S {
^
template.cpp:1:8: note: candidate expects 1 argument, 0 provided
template.cpp:1:8: note: constexpr S::S(S&&)
template.cpp:1:8: note: candidate expects 1 argument, 0 provided
clang gives a similar error.
On the other hand, the following compiles:
struct S {
template <class T> S(T) {}
};
void f(int) {}
int main() {
S s = S(f); // this line was changed
}
So what's going on here?
THE PROBLEM
The code you've written doesn't mean what you think it is, you are actually declaring a variable of type S having the name f; it is not constructing an unnamed entity of type S, with f as argument.
Note: When you change the line into S s = S(f) you are however declaring a variable named s of type S, initialized with a temporary S(f) (ie. the copy-constructor of S will be used to initialize s).
THE SOLUTION
Wrap the type in parenthesis, or use uniform-initialization (which was introduced in C++11).
(S) (f); // creates a temporary of type S initialized with `f`
S { f }; // c++11
THE REASON
The standard (n3797) says that T(x) is equivalent to T x when declaring a variable, as can be read in the below section:
8.3p6 Meaning of declarators [dcl.meaning]
In a declaration T D where D has the form
( D1 )
the type of the contained declarator-id is the same as of the
contained declarator-id in the declaration
T D1
Parentheses do not alter the type of the embedded declarator-id, but
they can alter the binding of complex declarators.
With your definition of struct S
int main() {
S(f); // 1 <-----+
S s(f); // 2 <-------+ // +---- SAME
S s1 ; // +---- SAME // 3 <-----+
S s2 = S(f) ; // 4 <-------+
}
1 & 3 Declares a variable f & s1 respectively of type S requires a constructor for initialization
2 & 4 construct a variable s & s2 respectively of type S using copy constructor (note here the f is not your function name)