最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - How to make a variable hidden in a header file - Stack Overflow

programmeradmin2浏览0评论

I have a template struct Distance that uses constexpr unsigned char mm2cm = 10

Since Distance is a template class, I must define mm2cm and Distance in a header file.

This header file is included by cpp files.

I want mm2cm to only be visible in this header file and not in the cpp files that include this header, ie:

Distance.hpp

constexpr unsigned char mm2cm = 10;

template <int offset>
struct Distance{
    int mm;
    int convToCm() const { return offset + mm2cm * mm; }
};

Main.cpp

#include "Distance.hpp"
#include <iostream>

int main(){
    //I do not want to be able to use mm2mm outside Distance.hpp, as follows
    std::cout << (int)mm2cm << std::endl; 
    
}

One way I could solve this is using #define mm2cm 10 and #undef mm2cm at the beggining and end of the header file (instead of constexpr unsigned char mm2cm = 10.

However, a lot of people discourage the use of macros for reasons. This post lists some reasons why), and this website states that:

In general, the const keyword is preferred for defining constants and should be used instead of #define.

Another way I could solve this is by making mm2cmm a private static member of Distance.

However, in the actual, larger problem I am trying to solve, I have multiple variables that I only want to be visible in this header file, and making all of them private static members will make my class look ugly (in other words, there must be a better way than this solution).

I would be most grateful if someone could provide me the most optimal way to ensure mm2cm is only visible to Distance or only visible within this header file.


A prior edition of this post used a type template parameter. This has been changed to a non-type template parameter since the actual problem I am trying to solve uses a non-type template parameter.

I have a template struct Distance that uses constexpr unsigned char mm2cm = 10

Since Distance is a template class, I must define mm2cm and Distance in a header file.

This header file is included by cpp files.

I want mm2cm to only be visible in this header file and not in the cpp files that include this header, ie:

Distance.hpp

constexpr unsigned char mm2cm = 10;

template <int offset>
struct Distance{
    int mm;
    int convToCm() const { return offset + mm2cm * mm; }
};

Main.cpp

#include "Distance.hpp"
#include <iostream>

int main(){
    //I do not want to be able to use mm2mm outside Distance.hpp, as follows
    std::cout << (int)mm2cm << std::endl; 
    
}

One way I could solve this is using #define mm2cm 10 and #undef mm2cm at the beggining and end of the header file (instead of constexpr unsigned char mm2cm = 10.

However, a lot of people discourage the use of macros for reasons. This post lists some reasons why), and this website states that:

In general, the const keyword is preferred for defining constants and should be used instead of #define.

Another way I could solve this is by making mm2cmm a private static member of Distance.

However, in the actual, larger problem I am trying to solve, I have multiple variables that I only want to be visible in this header file, and making all of them private static members will make my class look ugly (in other words, there must be a better way than this solution).

I would be most grateful if someone could provide me the most optimal way to ensure mm2cm is only visible to Distance or only visible within this header file.


A prior edition of this post used a type template parameter. This has been changed to a non-type template parameter since the actual problem I am trying to solve uses a non-type template parameter.

Share Improve this question edited Nov 17, 2024 at 1:45 Remy Lebeau 602k36 gold badges508 silver badges853 bronze badges asked Nov 16, 2024 at 21:52 timmy geetimmy gee 6431 silver badge12 bronze badges 13
  • OT: Why do you have the explicit conversion (the cast) when you print the value of mm2cm? Whenever you feel the need to do a C-style explicit conversion like that, you should take it as a sign that you're probably are doing something wrong. – Some programmer dude Commented Nov 16, 2024 at 22:15
  • just put it in a namespace called detail , that universally means private among C++ developers, as in, don't access it as i will change it in any day, it is an implementation detail – Ahmed AEK Commented Nov 16, 2024 at 22:15
  • 2 "making all of them private static members will make my class look ugly" - How so? You want them to be private and they are static in nature, so making them private and static constexpr would be my first choice. – Ted Lyngmo Commented Nov 17, 2024 at 0:04
  • 1 @timmygee If they are only used once, then move them into the functions where they are used. int convToCm() const { constexpr int mm2cm = 10; return offset + mm2cm * mm; } – Ted Lyngmo Commented Nov 17, 2024 at 0:15
  • 1 Agree with @TedLyngmo. I don't see any problem (esthetic or any other) to use as many private static constexpr members as you need (or use a local in a method if it is used only once). – wohlstad Commented Nov 17, 2024 at 7:51
 |  Show 8 more comments

2 Answers 2

Reset to default 0

Reviewing your requirements, this is the best I could come up with...

template <int offset>
struct Distance {
private:
    enum Constants : unsigned char {
        mm2cm = 10,
    };
public:
    int mm;
    int convToCm() const { return offset + mm2cm * mm; }
};

It hides the value in an enum, and can be used with other constants.

convToCm() looks like it is the wrong way (looks like it converts cm to mm.)

If mm2cm was an object or function, then it would inhibit the compiler's ability to optimize. We could do a base class implementation, but that would still have the "ugly" multiple private / static members.

The use of integer offset as a template is awkward for the compiler.

Distance<10> value;
Distance<12> value2;

Requires the compiler to generate

int Distance<10>::convToCm() const;
int Distance<12>::convToCm() const;

Both of which have identical code except for the template parameter 10/12. This would be more problematic if the objects were in a container, where std::vector< Distance<10> > requires different code to std::vector< Distance<12> >

Try this:

Distance.hpp

#ifndef DISTANCE_HPP
#define DISTANCE_HPP

template <typename UnitType>
struct Distance {
    UnitType mm;
    UnitType convToCm() const; // Declaration only
};

#endif // DISTANCE_HPP

Distance.cpp

#include "Distance.hpp"

namespace { // Anonymous namespace hides this constant
    constexpr unsigned char mm2cm = 10;
}

template <typename UnitType>
UnitType Distance<UnitType>::convToCm() const {
    return mm * mm2cm;
}

// Explicit instantiations (if needed)
template struct Distance<int>;
template struct Distance<float>;

Main.cpp

#include "Distance.hpp"
#include <iostream>

int main() {
    Distance<int> dist{100};
    std::cout << dist.convToCm() << std::endl; // Outputs 1000

    // The following line will fail to compile, as mm2cm is not visible:
    // std::cout << (int)mm2cm << std::endl;

    return 0;
}
发布评论

评论列表(0)

  1. 暂无评论