开发者

using variables to decide type of class or namespace

开发者 https://www.devze.com 2023-01-05 21:14 出处:网络
Alright, so i had the bright idea of using namespaces and an if statement to change the outcome of variables, in PHP i imagine i could\'ve used concatenation however c++ doesnt seem to have concatenat

Alright, so i had the bright idea of using namespaces and an if statement to change the outcome of variables, in PHP i imagine i could've used concatenation however c++ doesnt seem to have concatenation as far as i can see so far.

so is there a way to get this code to work?

namespace Blue
{

int seven = 7;
int eight = 8;


}

namespace Red
{

int seven = 1;
int eight = 2;

}

and here is the main cpp file

int choice;

cin >> choice;

if(choice == 1)
{
    char A[] = "Blue";

}else if(choice == 2){

    char A[] = "Red";

}

开发者_Go百科cout << A::seven << endl;

cout << A::eight << endl;


You can't decide which namespace to use in runtime.

This sort of things is compile-time only.


I don't think there is a way to do this, and if there were, it's probably a bad idea. You would normally accomplish this behavior in C++ using polymorphism, e.g.:

class Color {
  virtual int seven() = 0;
  virtual int eight() = 0;
};
class Blue : public Color {
  int seven() { return 7; }
  int eight() { return 8; }
};
class Red : public Color {
  int seven() { return 1; }
  int eight() { return 2; }
};

and then:

int choice;
Color* color;

cin << choice;
if (choice == 1)
  color = new Blue;
else
  color = new Red;

cout << color->seven() << endl;
cout << color->eight() << endl;

delete color;


It's not possible to assign classes or namespaces and make the outcome of namelookup dependent on this. But you can assign the address of variables. So in your example, you could say

array<int*, 2> nums;    
if(choice == 1)
{
    array<int*, 2> blues = {{ &Blue::seven, &Blue::eight }};
    nums = blues;
} else if(choice == 2) {
    array<int*, 2> reds = {{ &Red::seven, &Red::eight }};
    nums = reds;
}

cout << *nums[0] << endl;
cout << *nums[1] << endl;

However in this case you can put the print into each respective if clause, which looks easier to me

if(choice == 1)
{
    cout << Blue::seven << endl;
    cout << Blue::eight << endl;
} else if(choice == 2) {
    cout << Red::seven << endl;
    cout << Red::eight << endl;
}

If you accesses are often, you may wish to put the colors into a single data-structure

typedef std::array<int, NumberCount> number_array;
typedef std::array<number_array, ColorCount> color_array;

color_array colors = {{ {{ 7, 8 }}, {{ 1, 2 }} }};

So you could use an index, maybe using enumerations for the color names instead of raw numbers

int arrayIndex = -1;
if(choice == 1)
{
    arrayIndex = 0;
} else if(choice == 2) {
    arrayIndex = 1;
}

if(arrayIndex != -1) {
    cout << colors[arrayIndex][0] << endl;
    cout << colors[arrayIndex][1] << endl;
}

This way you can also iterate over the colors (using array's size() function or its iterator interface). array is part of TR1, C++0x and Boost.


No that won't work because the namespace is evaluated at compile time and the contents of A are not known until runtime. I run into this a lot with my projects. One of the languages I interface with has dynamic typing known at run time and C++ uses compile time resolution for the typing. Usually you get around this with a case statement that calls specialized templated functions.

    enum Choice
    {
        blue,
        red
    }

    template <Choice c>
    struct Option
    {
        enum {seven=0};
        enum {eight=0};
    };

    template <>
    struct Option<blue>
    {
        enum {seven=7};
        enum {eight=8};
    }

    template <>
    struct Option<red>
    {
        enum {seven=1};
        enum {eight=2};
    }

    ...

    switch (choice)
    {
    case red:
        cout << Option<red>::seven << endl;
        cout << Option<red>::eight << endl;
    case blue:
        cout << Option<blue>::seven << endl;
        cout << Option<blue>::eight << endl;
    }

note, that you can't do something like

cout << Option<choice>::seven << endl

because the value of choice isn't known at compile time.

They way I like to view it: anything that's in a templated argument has to be known at compile time, anything that's only known at run time needs to go in a case statement which then calls the properly templated function.

Note that this is a uber complicated way of changing the values of seven and eight, which could be done easier another way (say, a map), but there are cases where this is very useful. I do it all the time.


You can't do that in C++ directly. However, you can use a std::map to achieve a similar result:

std::map<std::string, int> Blue;
Blue["seven"] = 7;
Blue["eight"] = 8;
assert(Blue["seven"] == 7);


<EDIT>This doesn't address the namespace issue, but since you mentioned string concatenation...</EDIT>

To concatenate strings in C++:

string a = "Hello, ";
string b = "World!";
string c = a + b;

I'm not exactly sure what you mean by the code in your question not working. You're outputting the two strings on separate lines (endl is equivalent to "\n" + flushing the stream).

Edit

I think the problem is that you're trying to use char arrays. While these technically are strings, they aren't the C++ way of doing strings. If you want to do strings like C, use the C standard library strcat (or preferably the safer versions that likely come with your compiler).


It seems to me that you don't really care about the question you ask, but really want to know, "What's the point of namespaces?"

Namespace are used mainly to segrate class (and other data elements) whch have the same name from each other.

Back before C++ was standardized, there was no std::string, but every 3rd-party library had it's own. So, if you want to both Widgetworks library for some things, and CoolObjects library for other things, you'd have a problem if you merely wrote:

#include "widgetworx.h"
#include "coolobjects.h"

Because both would define a class called string. So the standardization committee realized that if they added their own string, now you'd have three. There solution was namespaces. The Standard string class (and all the other strandard classes) would be in namespace std, and it would only be used you specifically said to use it. Further, you could manually wrap the older header files into namespaces to seaprate them:

namespace WW
{
    #include "widgetworx.h"
}
namespace CO
{
    #include "coolobjects.h"
}

and then just use the piece that you want:

using CO::matrix;
using WW::complex;
using std::string;
0

精彩评论

暂无评论...
验证码 换一张
取 消