Writing a method for a templated private member

I am trying to understand the coding by inserting std::cout's to print messages at the console. After inserting the following coding:
1
2
3
4
5
6
	std::vector<int> v{ 1, 2, 3 };
	addable<std::vector<int>>{v}.add(10);
	for (auto it = v.begin(); it != v.end(); ++it)
		std::cout << *it << " ";
	std::cout << std::endl;


I realized that the for statement did not do what I wanted. I want to print the result in T val in the addable class. How do you write this method?



Here is the full coding. It uses the C++17 new features.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <cassert>
#include <string>
#include <vector>
#include <cstdio>
#include <iostream>

template <typename T>
class addable
{
    T val;

public:
    addable(T v) : val{v} {}

#if 0
    // The C++11 way
	std::cout << "C++11 way" << std::endl;
    template <typename U>
    std::enable_if_t<!std::is_same<T, std::vector<U>>::value, T>
    add(U x) const { return val + x; }

    template <typename U>
    std::enable_if_t<std::is_same<T, std::vector<U>>::value, std::vector<U>>
    add(U x) const {
        auto copy = val;

        for (auto &n : copy) {
            n += x;
        }
		return copy;
    }
#else
	// The C++17 way
    template <typename U>
    T add(U x) const {
        if constexpr (std::is_same_v<T, std::vector<U>>) {
            auto copy = val;
            for (auto &n : copy) {
                n += x;
            }
			std::cout << "C++17 way" << std::endl;
            return copy;
        } else {
            return val + x;
        }
    }
#endif

};

int main()
{
	using namespace std::string_literals;

	std::cout << "addable<int> " << addable<int>{1}.add(2) << std::endl;
	std::cout << "addable<float> " << addable<float>{1.0}.add(2) << std::endl;
	std::cout << "addable<std::string> " << addable<std::string>{"aa"}.add("bb") << std::endl;

	std::vector<int> v{ 1, 2, 3 };
	addable<std::vector<int>>{v}.add(10);
	for (auto it = v.begin(); it != v.end(); ++it)
		std::cout << *it << " ";
	std::cout << std::endl;

	std::vector<std::string> sv{ "a", "b", "c" };
	for (auto it = sv.begin(); it != sv.end(); ++it)
		std::cout << "sv = " << *it << " ";
	std::cout << std::endl;
	
    std::cout << "addable<int> " << addable<int>{2}.add(3) << std::endl;
    std::cout << "addable<std::string> " << addable<std::string>{"aa"s}.add("bb"s) << std::endl;

    std::vector<int> v1 {1, 2, 3};
    std::vector<int> v2 {11, 12, 13};
    assert(addable<std::vector<int>>{v1}.add(10) == v2);

    std::vector<std::string> sv1 {"a", "b", "c"};
    std::vector<std::string> sv2 {"az", "bz", "cz"};
    assert(addable<std::vector<std::string>>{sv1}.add("z"s) == sv2);
}
C++17:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <type_traits>
#include <iterator>
#include <vector>
#include <list>
#include <string>

namespace detail
{
    template < typename, typename = void > struct is_sequence : std::false_type {};

    template < typename T > // just checks compatibility with std::begin. (TO DO: also check std::end)
    struct is_sequence< T, std::void_t< decltype( std::begin( std::declval<T>() ) ) > > : std::true_type {};
}

template < typename T > struct addable
{
    constexpr addable( T v ) noexcept( std::is_nothrow_move_constructible_v<T> ) : val( std::move(v) ) {}

    template < typename U > constexpr T operator+ ( U rhs ) const
    {

        if constexpr( detail::is_sequence<T>::value )
        {
            T copy(val) ;
            for( auto& v : copy ) v += rhs ;
            return copy ;
        }

        else return val + rhs ;
    }

    private: T val ;
};

int main()
{
    constexpr addable i = 22 ; // class template argument deduction
    std::cout << i+32 << '\n' ; // 54
    static_assert( i+32 == addable(i+20)+12 ) ;

    addable vec( std::vector<int>{ 0, 1, 2, 3, 4, 5, 6 } ) ;
    for( auto v : vec+32 ) std::cout << v << ' ' ; // 32 33 34 35 36 37 38
    std::cout << '\n' ;

    addable lst( std::list<std::string>{ "This", "is", "C++17" } ) ;
    for( const auto& v : lst + '.' ) std::cout << v << ' ' ; // This. is. C++17.
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/20bebe1e20c8ad84
JL,

Your response is way above my comprehension level. I was thinking of a method like this T getVal() {return val;}, where the method gets access to a private data member.
> I was thinking of a method like this T getVal() {return val;},
> where the method gets access to a private data member.

This is obviously possible; though add() does not modify the member object val in any way.

This is perhaps what you want to do: use the value returned by add. For example:
1
2
std::vector<int> v1 {1, 2, 3}; 
for( int v : addable<std::vector<int>>{v1}.add(10) ) std::cout << '\n' ;
I stripped the program down to the basics. There is a red squiggly line under the dot in the for statement before the add function. See the coding below.

The coding also does not compile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <cassert>
#include <string>
#include <vector>
#include <cstdio>
#include <iostream>

template <typename T>
class addable
{
	T val;

public:
	addable(T v) : val(v) {}

	// The C++17 way
	template <typename U>
	T add(U x) : const {
		if constexpr(std::is_same_v<T, std::vector<U>>) {
			auto copy = val;
			for (auto &n : copy) {
				n += x;
			}
			return copy;
		} else {
			return val + x;
		}
	}
};

int main()
{
	addable<int>{1}.add(2);
	addable<float>{1.0}.add(2.0);
	addable<std::string>{"aa"}.add("bb");

	std::vector<int> v{ 1, 2, 3 };
	for (int v : addable < std::vector<int>{v}.add(10))
		std::cout << v << ' ';
	std::cout << '\n';
}
With the syntax errors (lines 17, 37 in the original code) corrected, it does compile cleanly:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <cassert>
#include <string>
#include <vector>
#include <cstdio>
#include <iostream>

template <typename T>
class addable
{
	T val;

public:
	addable(T v) : val(v) {}

	// The C++17 way
	template <typename U>
	T add(U x) const {
		if constexpr( std::is_same_v<T, std::vector<U>> ) {
		// note: if std::is_same_v is not supported, write as: 
		// if constexpr( std::is_same<T, std::vector<U>>::value ) {
		
			auto copy = val;
			for (auto &n : copy) {
				n += x;
			}
			return copy;
		} else {
			return val + x;
		}
	}
};

int main()
{
	addable<int>{1}.add(2);
	addable<float>{1.0}.add(2.0);
	addable<std::string>{"aa"}.add("bb");

	std::vector<int> v{ 1, 2, 3 };
	for (int item : addable < std::vector<int> >{v}.add(10))
		std::cout << item << ' ';
	std::cout << '\n';
}

http://coliru.stacked-crooked.com/a/2e84ce1b832ee3d6
Last edited on
Thanks JL, the program compiles and works.

But now, I am trying to display the results of adding two strings. Although I made the for statement similar to the for statement for the adding of integers, the program did not compile. Here is the coding:

1
2
3
	std::vector<std::string> sv{ "a", "b", "c" };
	for (std::string str : std::vector<std::string>{sv}.add("z"))
		std::cout << str << std::endl;


One more thing, when I use the Developer Command Prompt for VS 2017, I have add /std:c++17 to compile to get the C++17 extensions. When I make a Project/Solution for the program, I get an error message that I need the C++17 extension. How do I get the C++17 extensions for a Project/Solution?
> the program did not compile.

In general, it is far more likely that you would receive a helpful answer to your question if you are clear and precise about the problem that you encounter, 'The program did not compile' does not say very much; at the very least reproduce the verbatim error diagnostic issued by the compiler.

The problem here appears to be that you intended to write:
1
2
// for (std::string str : std::vector<std::string>{sv}.add("z"))
for (std::string str : addable < std::vector<std::string> >{sv}.add("z"))



> How do I get the C++17 extensions for a Project/Solution?

Right click on the project in the solution explorer, choose 'properties'
In the property pages, select: Configuration - 'All Configurations'
In the Configuration properties pane (on the left), select: C/C++ => Language
I the pane on the right, for C++ Language Standard, choose ISO C++17 Standard (/std:C++17)

Or choose ISO C++ Latest Draft Standard (/std:c++latest) to enable C++20 features to the extent that they have been implemented (mainly the standard library).
Thank you very much for the setup information to get the C++17 extensions. It will make building of the program faster, and I can use the Debugger to see how the program works.

Here is the latest version of the program. I made the correction you described.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <cassert>
#include <string>
#include <vector>
#include <cstdio>
#include <iostream>

template <typename T>
class addable
{
	T val;

public:
	addable(T v) : val(v) {}

	// The C++17 way
	template <typename U>
	T add(U x) const {
		if constexpr(std::is_same_v<T, std::vector<U>>) {
			auto copy = val;
			for (auto &n : copy) {
				n += x;
			}
			return copy;
		}
		else {
			return val + x;
		}
	}
};

int main()
{
	using namespace std::string_literals;

	addable<int>{1}.add(2);
	addable<float>{1.0}.add(2.0);
	addable<std::string>{"aa"}.add("bb");

	std::vector<int> v{ 1, 2, 3 };
	for (int v : addable < std::vector<int>>{v}.add(10))
		std::cout << v << ' ';
	std::cout << '\n';

	std::vector<std::string> sv{ "a", "b", "c" };
	for (std::string str : addable<std::vector<std::string>>{ sv }.add("z"))
		std::cout << str << std::endl;

	return 0;
}

The program did not compile, and I have provided a partial listing of the error output. I could not copy the error output from the command line listing before.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1
1>testprb.cpp
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(26): warning C4244: 'return': conversion from 'double' to 'float', possible loss of data
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(36): note: see reference to function template instantiation 'T addable<T>::add<double>(U) const' being compiled
1>        with
1>        [
1>            T=float,
1>            U=double
1>        ]
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(36): note: see reference to function template instantiation 'T addable<T>::add<double>(U) const' being compiled
1>        with
1>        [
1>            T=float,
1>            U=double
1>        ]
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(27): error C2784: 'std::reverse_iterator<_RanIt> std::operator +(reverse_iterator<_RanIt>::difference_type,const std::reverse_iterator<_RanIt> &)': could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'const char *'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\xutility(1404): note: see declaration of 'std::operator +'
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(45): note: see reference to function template instantiation 'T addable<T>::add<const char*>(U) const' being compiled
1>        with
1>        [
1>            T=std::vector<std::string,std::allocator<std::string>>,
1>            U=const char *
1>        ]
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(45): note: see reference to function template instantiation 'T addable<T>::add<const char*>(U) const' being compiled
1>        with
1>        [
1>            T=std::vector<std::string,std::allocator<std::string>>,
1>            U=const char *
1>        ]
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(27): error C2784: 'std::_Array_const_iterator<_Ty,_Size> std::operator +(ptrdiff_t,std::_Array_const_iterator<_Ty,_Size>)': could not deduce template argument for 'std::_Array_const_iterator<_Ty,_Size>' from 'const char *'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\xutility(1990): note: see declaration of 'std::operator +'
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(27): error C2784: 'std::_Array_iterator<_Ty,_Size> std::operator +(ptrdiff_t,std::_Array_iterator<_Ty,_Size>)': could not deduce template argument for 'std::_Array_iterator<_Ty,_Size>' from 'const char *'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\xutility(2120): note: see declaration of 'std::operator +'
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(27): error C2784: 'std::move_iterator<_RanIt> std::operator +(move_iterator<_RanIt>::difference_type,const std::move_iterator<_RanIt> &)': could not deduce template argument for 'const std::move_iterator<_RanIt> &' from 'const char *'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\xutility(2269): note: see declaration of 'std::operator +'
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(27): error C2784: 'std::_String_view_iterator<_Traits> std::operator +(const _String_view_iterator<_Traits>::difference_type,std::_String_view_iterator<_Traits>) noexcept': could not deduce template argument for 'std::_String_view_iterator<_Traits>' from 'const char *'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\xstring(555): note: see declaration of 'std::operator +'
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(27): error C2784: 'std::_String_const_iterator<_Mystr> std::operator +(_String_const_iterator<_Mystr>::difference_type,std::_String_const_iterator<_Mystr>)': could not deduce template argument for 'std::_String_const_iterator<_Mystr>' from 'const char *'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\xstring(1372): note: see declaration of 'std::operator +'
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(27): error C2784: 'std::_String_iterator<_Mystr> std::operator +(_String_iterator<_Mystr>::difference_type,std::_String_iterator<_Mystr>)': could not deduce template argument for 'std::_String_iterator<_Mystr>' from 'const char *'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\xstring(1490): note: see declaration of 'std::operator +'
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(27): error C2784: 'std::basic_string<_Elem,_Traits,_Alloc> std::operator +(const std::basic_string<_Elem,_Traits,_Alloc> &,const std::basic_string<_Elem,_Traits,_Alloc> &)': could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'const std::vector<std::string,std::allocator<_Ty>>'
1>        with
1>        [
1>            _Ty=std::string
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\xstring(3727): note: see declaration of 'std::operator +'
1>c:\c++17stl\chapter01\testprb\testprb\testprb.cpp(27): error C2784: 'std::basic_string<_Elem,_Traits,_Alloc> std::operator +(const _Elem *const ,const std::basic_string<_Elem,_Traits,_Alloc> &)': could not deduce template argument for 'const _Elem *const ' from 'const 
In addable<std::vector<std::string>>{ sv }.add("z"),
std::is_same_v<T, std::vector<U>> would evaluate to false
( T is std::vector<std::string> and std::vector<U> is std::vector<const char*> )

Any of these (where the type U is std::string) would work:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main()
{
    using namespace std::string_literals;

    // ...

    std::vector<std::string> sv{ "a", "b", "c" };

    // add( std::string("z") ) : deduced to add<std::string>
    for (std::string str : addable<std::vector<std::string>>{ sv }.add( std::string("z") ) )
        std::cout << str << '\n';

    // add( "z"s ) : deduced to add<std::string> (using namespace std::string_literals)
    for (std::string str : addable<std::vector<std::string>>{ sv }.add( "z"s ) )
        std::cout << str << '\n';

    // add<std::string>( "z" ) ) : implicit converstion from const char* to std::string
    for (std::string str : addable<std::vector<std::string>>{ sv }.add<std::string>( "z" ) )
        std::cout << str << '\n';
}
You're the greatest JL. All three suggestions worked.

More questions:

What does the statement using namespace std::string_literals do? I know that it allows you to add an 's' after a string to explicitly say that I am a string instead of a char*. But, what else does it allow you to do?

The original program had the preprocessor command #if 0 . What does it do? Where does the 0 come from?
> What does the statement using namespace std::string_literals do?
> I know that it allows you to add an 's' after a string to explicitly say that I am a string instead of a char*.
> But, what else does it allow you to do?

I doesn't do anything else other than allow us to use the four library-defined string literals.
http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s


> #if 0 . What does it do?

See
http://en.cppreference.com/w/cpp/preprocessor/conditional
https://gcc.gnu.org/onlinedocs/cpp/Conditionals.html#Conditionals
Thank you, JL.

As for the #if 0 , it appears the author wanted to show how the C++11 way was done but not implement it.

Thank you very much.
Topic archived. No new replies allowed.