------ foo.cpp : BEGIN ------
#include <cassert>
#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <fstream>
using namespace std;
int main ()
{
ifstream f("foo.in", ios_base::binar y);
assert (f);
istream_iterato r<string> b(f), e;
cout << "(1) File : ";
copy (b, e, ostream_iterato r<string> (cout, " "));
cout << endl;
cout << "(2) File : ";
copy (b, e, ostream_iterato r<string> (cout, " "));
cout << endl;
return 0;
}
------ foo.cpp : END --------
------ Compilation & Run : BEGIN ------
$ g++ --version
g++ (GCC) 3.3.1 (cygming special)
[---omitted---]
$ g++ -mno-cygwin foo.cpp
$ a
(1) File : abc xyz ijk pqr
(2) File : abc
------ Compilation & Run : END --------
Why do two copy()'s produce different output?
--
Alex Vinokur http://mathforum.org/library/view/10978.html http://sourceforge.net/users/alexvn 9 3182
Alex Vinokur wrote: ------ foo.cpp : BEGIN ------ #include <cassert> #include <vector> #include <string> #include <iostream> #include <iterator> #include <fstream> using namespace std;
int main () { ifstream f("foo.in", ios_base::binar y); assert (f); istream_iterato r<string> b(f), e;
cout << "(1) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
cout << "(2) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
return 0; } ------ foo.cpp : END --------
------ Compilation & Run : BEGIN ------
$ g++ --version g++ (GCC) 3.3.1 (cygming special) [---omitted---]
$ g++ -mno-cygwin foo.cpp
$ a (1) File : abc xyz ijk pqr (2) File : abc
------ Compilation & Run : END --------
Why do two copy()'s produce different output?
Probably because you didn't rewind the stream. The 'istream_iterat or'
holds a reference to the stream it's initialised with. Any attempt to
read past the end of the file produce undefined behaviour.
Victor
"Victor Bazarov" <v.********@com Acast.net> wrote in message news:rz******** *****@newsread1 .dllstx09.us.to .verio.net... Alex Vinokur wrote:
[snip] Why do two copy()'s produce different output?
Probably because you didn't rewind the stream. The 'istream_iterat or' holds a reference to the stream it's initialised with. Any attempt to read past the end of the file produce undefined behaviour.
[snip]
Something like:
------ foo1.cpp : BEGIN ------
#include <cassert>
#include <string>
#include <iostream>
#include <iterator>
#include <fstream>
using namespace std;
int main ()
{
ifstream f("foo.in");
assert (f);
istream_iterato r<string> b(f), e;
cout << distance (b, e) << endl;
f.seekg (0, ios::beg);
cout << distance (b, e) << endl;
return 0;
}
------ foo1.cpp : END --------
------ Run : BEGIN ------
$ a
4
1
------ Run : END --------
What happened to 'b' after first 'distance'?
Where should one put 'seekg' (rewind) to get the same result after second 'distance'?
--
Alex Vinokur http://mathforum.org/library/view/10978.html http://sourceforge.net/users/alexvn
Alex Vinokur wrote: "Victor Bazarov" <v.********@com Acast.net> wrote in message news:rz******** *****@newsread1 .dllstx09.us.to .verio.net...
Alex Vinokur wrote: [snip]
Why do two copy()'s produce different output?
Probably because you didn't rewind the stream. The 'istream_iterat or' holds a reference to the stream it's initialised with. Any attempt to read past the end of the file produce undefined behaviour.
[snip]
Something like:
------ foo1.cpp : BEGIN ------ #include <cassert> #include <string> #include <iostream> #include <iterator> #include <fstream> using namespace std;
int main () { ifstream f("foo.in"); assert (f); istream_iterato r<string> b(f), e;
cout << distance (b, e) << endl; f.seekg (0, ios::beg); cout << distance (b, e) << endl;
return 0; } ------ foo1.cpp : END --------
------ Run : BEGIN ------
$ a 4 1
------ Run : END --------
What happened to 'b' after first 'distance'?
'distance' uses operator++ to count the number of increments. That
changes the original iterator, doesn't it?
Where should one put 'seekg' (rewind) to get the same result after second 'distance'?
Nowhere. Don't use 'distance'. Perhaps it's a bug in your library
implementation. Did you check how 'distance' worked? The trouble
with 'istream_iterat or' is that the connection between it and the
stream is mutating even after you make a copy of the iterator. You
might get lucky that your stream can be brought back to the same
state somehow, or you might never get lucky, and the stream, once it
has been read, can never go back to its beginning...
Why do you need to do that, anyway?
Victor
"Victor Bazarov" <v.********@com Acast.net> wrote in message news:ux******** *****@newsread1 .dllstx09.us.to .verio.net... Alex Vinokur wrote: "Victor Bazarov" <v.********@com Acast.net> wrote in message news:rz******** *****@newsread1 .dllstx09.us.to .verio.net...
Alex Vinokur wrote: [snip]
Why do two copy()'s produce different output?
Probably because you didn't rewind the stream. The 'istream_iterat or' holds a reference to the stream it's initialised with. Any attempt to read past the end of the file produce undefined behaviour.
[snip]
Something like:
------ foo1.cpp : BEGIN ------ #include <cassert> #include <string> #include <iostream> #include <iterator> #include <fstream> using namespace std;
int main () { ifstream f("foo.in"); assert (f); istream_iterato r<string> b(f), e;
cout << distance (b, e) << endl; f.seekg (0, ios::beg); cout << distance (b, e) << endl;
return 0; } ------ foo1.cpp : END --------
------ Run : BEGIN ------
$ a 4 1
------ Run : END --------
What happened to 'b' after first 'distance'?
'distance' uses operator++ to count the number of increments. That changes the original iterator, doesn't it?
Where should one put 'seekg' (rewind) to get the same result after second 'distance'?
Nowhere. Don't use 'distance'. Perhaps it's a bug in your library implementation.
Microsoft C++ Version 13.00.9466 for 80x86,
Borland C++ 5.5.1,
Digital Mars C++ 8.38n
produce the same behavior.
Did you check how 'distance' worked? The trouble with 'istream_iterat or' is that the connection between it and the stream is mutating even after you make a copy of the iterator. You might get lucky that your stream can be brought back to the same state somehow, or you might never get lucky, and the stream, once it has been read, can never go back to its beginning...
Why do you need to do that, anyway?
[snip]
I didn't need that, but I came across strange (to me) behavior of copy() while preparing my reply to thread http://groups-beta.google.com/group/...d64bb7a94fa3a/
Now I would like to understand this situation.
--
Alex Vinokur http://mathforum.org/library/view/10978.html http://sourceforge.net/users/alexvn
Alex Vinokur wrote: "Victor Bazarov" <v.********@com Acast.net> wrote in message news:ux******** *****@newsread1 .dllstx09.us.to .verio.net...
Alex Vinokur wrote:
"Victor Bazarov" <v.********@com Acast.net> wrote in message news:rz******** *****@newsread1 .dllstx09.us.to .verio.net...
Alex Vinokur wrote:
[snip]
>Why do two copy()'s produce different output?
Probably because you didn't rewind the stream. The 'istream_iterat or' holds a reference to the stream it's initialised with. Any attempt to read past the end of the file produce undefined behaviour.
[snip]
Something like:
------ foo1.cpp : BEGIN ------ #include <cassert> #include <string> #include <iostream> #include <iterator> #include <fstream> using namespace std;
int main () { ifstream f("foo.in"); assert (f); istream_iter ator<string> b(f), e;
cout << distance (b, e) << endl; f.seekg (0, ios::beg); cout << distance (b, e) << endl;
return 0; } ------ foo1.cpp : END --------
------ Run : BEGIN ------
$ a 4 1
------ Run : END --------
What happened to 'b' after first 'distance'?
'distance' uses operator++ to count the number of increments. That changes the original iterator, doesn't it?
Where should one put 'seekg' (rewind) to get the same result after second 'distance'?
Nowhere. Don't use 'distance'. Perhaps it's a bug in your library implementatio n.
Microsoft C++ Version 13.00.9466 for 80x86, Borland C++ 5.5.1, Digital Mars C++ 8.38n produce the same behavior.
Did you check how 'distance' worked? The trouble with 'istream_iterat or' is that the connection between it and the stream is mutating even after you make a copy of the iterator. You might get lucky that your stream can be brought back to the same state somehow, or you might never get lucky, and the stream, once it has been read, can never go back to its beginning...
Why do you need to do that, anyway?
[snip]
I didn't need that, but I came across strange (to me) behavior of copy() while preparing my reply to thread http://groups-beta.google.com/group/...d64bb7a94fa3a/
Now I would like to understand this situation.
If you feel like it, dig in the source of the C++ library (or libraries)
you're using. It seems that since 'copy' is a template, it probably gets
its arguments in the form of references (and not objects copied due to
passing by value). If it's so, the objects change while 'copy' does its
thing. How they change you can also discover by looking at the code. If
you find it interesting/revealing/puzzling, do post again.
You could also experiment with passing by value:
...
void foo(istream_ite rator b, istream_iterato r e)
{
std::copy(b, e, ...
}
int main()
{
...
foo(b, e);
// reset the stream
std::copy(b, e, ...
}
and see if it makes any difference...
V
On Wed, 21 Jul 2004 19:58:32 +0300, "Alex Vinokur"
<al****@big-foot.com> wrote: int main () { ifstream f("foo.in", ios_base::binar y); assert (f); istream_iterat or<string> b(f), e;
cout << "(1) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
cout << "(2) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
return 0; } (1) File : abc xyz ijk pqr (2) File : abc Why do two copy()'s produce different output?
When you take a copy of an input iterator, the original one is still
affected by changes to the copy. istream_iterato r can only be used for
1-pass algorithms. Rewinding the stream and then constructing a new
iterator from the stream is the only safe way to do a second pass.
e.g. something like:
int main ()
{
ifstream f("foo.in", ios_base::binar y);
assert (f);
istream_iterato r<string> b(f), e;
cout << "(1) File : ";
copy (b, e, ostream_iterato r<string> (cout, " "));
cout << endl;
f.seekg(0, std::ios_base:: beg);
b = istream_iterato r<string>(f);
cout << "(2) File : ";
copy (b, e, ostream_iterato r<string> (cout, " "));
cout << endl;
return 0;
}
Tom
"tom_usenet " <to********@hot mail.com> wrote in message news:iv******** *************** *********@4ax.c om... On Wed, 21 Jul 2004 19:58:32 +0300, "Alex Vinokur" <al****@big-foot.com> wrote:int main () { ifstream f("foo.in", ios_base::binar y); assert (f); istream_iterat or<string> b(f), e;
cout << "(1) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
cout << "(2) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
return 0; } (1) File : abc xyz ijk pqr (2) File : abc Why do two copy()'s produce different output? When you take a copy of an input iterator, the original one is still affected by changes to the copy. istream_iterato r can only be used for 1-pass algorithms. Rewinding the stream and then constructing a new iterator from the stream is the only safe way to do a second pass. e.g. something like:
int main () { ifstream f("foo.in", ios_base::binar y); assert (f); istream_iterato r<string> b(f), e;
cout << "(1) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
f.seekg(0, std::ios_base:: beg); b = istream_iterato r<string>(f);
It doesn't help. cout << "(2) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
return 0; }
Tom
Here is some program which demonstrates behavior of istream_iterato r.
====== File foo.cpp : BEGIN ======
#include <cassert>
#include <string>
#include <iostream>
#include <iterator>
#include <fstream>
using namespace std;
int main ()
{
ifstream f("foo.in", ios::binary);
assert (f);
cout << "Before istream_iterato r : tellg() = " << f.tellg() << endl;
cout << endl;
istream_iterato r<string> b(f), e;
cout << "--- First ---" << endl;
cout << "After istream_iterato r : tellg() = " << f.tellg() << endl;
cout << "Output-1.1 = ";
copy (b, e, ostream_iterato r<string> (cout, " "));
cout << endl;
cout << "After first copy : tellg() = " << f.tellg() << endl;
cout << "Output-1.2 = ";
copy (b, e, ostream_iterato r<string> (cout, " "));
cout << endl;
cout << endl;
cout << "--- Second ---" << endl;
f.clear();
f.seekg(0, ios::beg);
cout << "After clear and seekg : tellg() = " << f.tellg() << endl;
cout << "Output-2.1 = ";
copy (b, e, ostream_iterato r<string> (cout, " "));
cout << endl;
cout << "After second copy : tellg() = " << f.tellg() << endl;
cout << endl;
cout << "--- Third ---" << endl;
f.clear();
f.seekg(0, ios::beg);
cout << "After clear and seekg : tellg() = " << f.tellg() << endl;
b++;
cout << "After b++ : tellg() = " << f.tellg() << endl;
cout << "Output-3.1 = ";
copy (b, e, ostream_iterato r<string> (cout, " "));
cout << endl;
cout << "After third copy : tellg() = " << f.tellg() << endl;
cout << endl;
return 0;
}
====== File foo.cpp : END ========
====== Compilation & Run : BEGIN ======
$ g++ --version
g++ (GCC) 3.3.1 (cygming special)
[---omitted---]
$ g++ foo.cpp
$ a
Before istream_iterato r : tellg() = 0
--- First ---
After istream_iterato r : tellg() = 3
Output-1.1 = aaa bbb ccc ddd
After first copy : tellg() = -1
Output-1.2 = aaa
--- Second ---
After clear and seekg : tellg() = 0
Output-2.1 = aaa aaa bbb ccc ddd
After second copy : tellg() = -1
--- Third ---
After clear and seekg : tellg() = 0
After b++ : tellg() = 3
Output-3.1 = aaa bbb ccc ddd
After third copy : tellg() = -1
====== Compilation & Run : END ========
--
Alex Vinokur http://mathforum.org/library/view/10978.html http://sourceforge.net/users/alexvn
Alex Vinokur wrote: "tom_usenet " <to********@hot mail.com> wrote in message news:iv******** *************** *********@4ax.c om...
On Wed, 21 Jul 2004 19:58:32 +0300, "Alex Vinokur" <al****@big-foot.com> wrote:
int main () { ifstream f("foo.in", ios_base::binar y); assert (f); istream_iter ator<string> b(f), e;
cout << "(1) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
cout << "(2) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
return 0; } (1) File : abc xyz ijk pqr (2) File : abc Why do two copy()'s produce different output? When you take a copy of an input iterator, the original one is still affected by changes to the copy. istream_iterato r can only be used for 1-pass algorithms. Rewinding the stream and then constructing a new iterator from the stream is the only safe way to do a second pass. e.g. something like:
int main () { ifstream f("foo.in", ios_base::binar y); assert (f); istream_iterato r<string> b(f), e;
cout << "(1) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
f.seekg(0, std::ios_base:: beg); b = istream_iterato r<string>(f);
It doesn't help.
You probably also need to do
f.clear();
before f.seekg( ..
Once the EOF is reached, the stream becomes non-responsive until
you clear its error state.
V
cout << "(2) File : "; copy (b, e, ostream_iterato r<string> (cout, " ")); cout << endl;
return 0; }
Tom
[...]
"Victor Bazarov" <v.********@com Acast.net> wrote in message news:lG******** *****@newsread1 .dllstx09.us.to .verio.net...
[snip] If you feel like it, dig in the source of the C++ library (or libraries) you're using. It seems that since 'copy' is a template, it probably gets its arguments in the form of references (and not objects copied due to passing by value). If it's so, the objects change while 'copy' does its thing. How they change you can also discover by looking at the code. If you find it interesting/revealing/puzzling, do post again.
You could also experiment with passing by value:
... void foo(istream_ite rator b, istream_iterato r e) { std::copy(b, e, ... }
int main() { ... foo(b, e); // reset the stream std::copy(b, e, ... }
and see if it makes any difference...
V
We can see that there is no difference between passing by value and passing by reference because
a position of the pointer in istream 'f' (not istream_iterato r 'b') determines such behavior.
====== foo.cpp : BEGIN ======
#include <cassert>
#include <string>
#include <iostream>
#include <iterator>
#include <fstream>
using namespace std;
void copy_by_value(i stream_iterator <string> b, istream_iterato r<string> e)
{
copy (b, e, ostream_iterato r<string> (cout, " "));
}
void copy_by_ref(con st istream_iterato r<string>& b, const istream_iterato r<string>& e)
{
copy (b, e, ostream_iterato r<string> (cout, " "));
}
void test_by_value()
{
cout << "=== test_by_value ===" << endl;
ifstream f("foo.in", ios_base::binar y);
assert (f);
cout << "Before istream_iterato r : tellg() = " << f.tellg() << endl;
istream_iterato r<string> b(f), e;
cout << "After istream_iterato r : tellg() = " << f.tellg() << endl;
cout << "Output-1 =";
copy_by_value (b, e);
cout << endl;
cout << "After copy_by_value : tellg() = " << f.tellg() << endl;
cout << "Output-2 =";
copy (b, e, ostream_iterato r<string> (cout, " "));
cout << endl;
cout << endl;
}
void test_by_ref()
{
cout << "=== test_by_ref ===" << endl;
ifstream f("foo.in", ios_base::binar y);
assert (f);
cout << "Before istream_iterato r : tellg() = " << f.tellg() << endl;
istream_iterato r<string> b(f), e;
cout << "After istream_iterato r : tellg() = " << f.tellg() << endl;
cout << "Output-1 =";
copy_by_ref (b, e);
cout << endl;
cout << "After copy_by_ref : tellg() = " << f.tellg() << endl;
cout << "Output-2 =";
copy (b, e, ostream_iterato r<string> (cout, " "));
cout << endl;
cout << endl;
}
int main ()
{
test_by_value() ;
test_by_ref();
return 0;
}
====== foo.cpp : END ========
###### Run : BEGIN ######
=== test_by_value ===
Before istream_iterato r : tellg() = 0
After istream_iterato r : tellg() = 3
Output-1 =aaa bbb ccc ddd
After copy_by_value : tellg() = -1
Output-2 =aaa
=== test_by_ref ===
Before istream_iterato r : tellg() = 0
After istream_iterato r : tellg() = 3
Output-1 =aaa bbb ccc ddd
After copy_by_ref : tellg() = -1
Output-2 =aaa
###### Run : END ######
--
Alex Vinokur http://mathforum.org/library/view/10978.html http://sourceforge.net/users/alexvn This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
by: Bill Rudolph |
last post by:
The member function basic_ios::operator!() returns the bool result of
the basic_ios::fail() function which is true if either failbit or
badbit is set (This is per p. 616 of TC++PL by B. Stroustrup and p. 34
of Standard C++ IOStreams and Locales by Angelika Langer and Klaus
Kreft).
The implementation of the input stream iterator in the Langer and
Kreft book (see p. 129 to 130) uses the function:
void readElem()
|
by: Alex Vinokur |
last post by:
ofstream outfile ("out");
ifstream infile ("in");
istream_iterator<char> iter(infile), eos;
Is it possible to copy 'infile' to 'outfile' using 'iter' and 'eos'?
--
Alex Vinokur
mailto:alexvn@connect.to
http://mathforum.org/library/view/10978.html
|
by: NPC |
last post by:
Hi,
Is there any way to use an istream_iterator<> in a way which inserts each
element at the end of a newline character rather than a space character?
Could be it looks for any type of whitespace - not sure about that.
In particular, it would be nice to use it in a way which is similar to an
ostream_iterator:
std::vector<std::string> myVec;
/* add stuff to myVec */
|
by: alberto |
last post by:
I am learning STL with the book STL Tutorial and Reference guide (1 edition),
the following example don't run :
int main()
{
// Initialize array a with 10 integers:
int a = {12, 3, 25, 7, 11, 213, 7, 123, 29, -31};
// Find the first element equal to 7 in the array:
int* ptr = find(&a, &a, 7);
|
by: Shuch |
last post by:
Hi all,
i m trying to read from a file and then copy it into an array...my
code is as follow..it runs fine but i cant understand y it doesnt show
me any output??
here is my code...
using namespace std;
int Adj; //The matrix of adjacent nodes
int curr; //it gives the current index to retrieve the
neigbours of a node
int n=100;
| |
by: jmoy.matecon |
last post by:
I get an error while compiling the following program:
int main()
{
vector<int> v(istream_iterator<int>(cin),
istream_iterator<int>());
copy(v.begin(),v.end(),ostream_iterator<int>(cout,"\n"));
}
The errors I get are is:
|
by: Juha Nieminen |
last post by:
I'm using gcc 3.3.5. This code:
std::set<std::stringt(std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>());
gives a strange error message:
error: cannot use `::' in parameter declaration
If I try it this way:
|
by: arnuld |
last post by:
It works fine. any advice on making it better or if I can
improve my C++ coding skills:
/* C++ Primer - 4/e
*
* Chapter 9 - Sequential Containers
* exercise 9.18 - STATEMENT
* Write a program to copy elements from a list of "ints"
* to 2 "deques". The list elements that are even should go into one deque
* and even elements should go into 2nd deque.
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look !
Part I. Meaning of...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it.
First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed.
This is as boiled down as I can make it.
Here is my compilation command:
g++-12 -std=c++20 -Wnarrowing bit_field.cpp
Here is the code in...
| |
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own....
Now, this would greatly impact the work of software developers. The idea...
|
by: conductexam |
last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one.
At the time of converting from word file to html my equations which are in the word document file was convert into image.
Globals.ThisAddIn.Application.ActiveDocument.Select();...
|
by: TSSRALBI |
last post by:
Hello
I'm a network technician in training and I need your help.
I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs.
The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols.
I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
|
by: 6302768590 |
last post by:
Hai team
i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
|
by: bsmnconsultancy |
last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...
| |