과학 코드의 많은 상수, 변수를 다루는 C ++ 모범 사례


17

흐름에 존재하는 생물학적 물질로 유체 흐름을 시뮬레이션하는 코드를 개발 중입니다. 여기에는 몇 가지 추가 생물학적 모델과 결합 된 표준 Navier-Stokes 방정식이 포함됩니다. 많은 매개 변수 / 상수가 있습니다.

주요 계산을 처리하는 함수를 작성했지만 문제는 이러한 계산에 의존하는 많은 상수 / 매개 변수입니다. 함수에 10-20 개의 인수를 전달하는 것은 번거로운 것 같습니다.

하나의 대안은 모든 상수 전역 변수를 만드는 것이지만 이것이 C ++에서 눈살을 찌푸리는 것을 알고 있습니다.

함수에 대한 많은 입력을 처리하는 표준 방법은 무엇입니까? 구조체를 만들어서 대신 전달해야합니까?

감사합니다


7
가능하면 constexpr을 사용하여 컴파일 타임에 상수를 평가하도록하십시오. 나는 대부분을 별도의 헤더 파일에 포함하려고합니다. 변수의 경우 별도의 클래스에 이점이 있지만 함수에 전달하기 전에 클래스를 초기화해야하기 때문에 더 많은 버그가 발생할 수 있습니다.
Biswajit Banerjee

3
코드 샘플이 없으면 제대로 대답하기가 어렵습니다. 구조체를 만들어서 대신 전달해야합니까? 일반적으로 그렇습니다. 이것은 절대적으로 일반적인 방법입니다. 매개 변수 / 상수를 의미별로 그룹화하십시오.
Kirill

1
"하나의 대안은 모든 상수 전역 변수를 확인하는 것입니다,하지만 난이 C ++로 눈살을 찌푸리게 알고" 그것은인가?
Monica와의 가벼움 경주

1
그들은 정말 정말 상수입니까? 다른 도메인에 모델을 적용하려면 어떻게합니까? 나는 작은 수업에 넣는 것이 좋습니다. 최소한 미래에는 약간의 유연성이 있습니다
André

@ André 대부분은 매개 변수 파일을 통해 사용자가 제어하므로 클래스 솔루션이 최고라는 데 동의합니다.
EternusVia 2019

답변:


13

실행하기 전에 변경되지 않는 상수가 있으면 헤더 파일로 선언하십시오.

//constants.hpp
#ifndef PROJECT_NAME_constants_hpp
#define PROJECT_NAME_constants_hpp
namespace constants {
  constexpr double G        = 6.67408e-11;
  constexpr double M_EARTH  = 5.972e24;
  constexpr double GM_EARTH = G*M_EARTH; 
}
#endif

//main.cpp
using namespace constants;
auto f_earth = GM_EARTH*m/r/r;  //Good
auto f_earth = G*M_EARTH*m/r/r; //Also good: compiler probably does math here too

이 작업을 수행하려는 이유는 컴파일러가 런타임 전에 상수 값을 미리 계산할 수 있기 때문에 값이 많으면 좋습니다.

간단한 클래스를 사용하여 값을 전달할 수도 있습니다.

class Params {
 public:
  double a,b,c,d;
  Params(std::string config_file_name){
    //Load configuration here
  }
};

void Foo(const Params &params) {
  ...
}

int main(int argc, char **argv){
  Params params(argv[1]);
  Foo(params);
}

모든 훌륭한 답변이지만 수업 솔루션은 내 상황에 가장 적합합니다.
EternusVia 2019

8
변수를 전역 변수로 만들면 다른 전역 기호를 constexpr밟지 않도록 변수 로 묶어야합니다 namespace. 라는 전역 변수를 사용하면 G문제가 발생합니다.
Wolfgang Bangerth 's

1
_를 포함하는 경비원을 왜 이끌어야합니까? _로 시작하는 것을 쓰면 안되며 컴파일러 변수와 충돌 할 위험이 있습니다. 당신은 같은 일을해야합니다 ifndef PROJECT_NAME_FILE_NAME_EXTENSION. 또한 왜 상수를 대문자로 사용했는지는 모르지만 포함 가드 매크로는 아닙니다. 일반적으로 모든 매크로, 특히 위생적이지 않기 때문에 모든 매크로를 대문자로 사용하려고합니다. 상수 대문자는 일반적으로 의미가 없습니다 . G그것의 SI 때문에 괜찮지 만, mass_earth가 더 적절하고, 전역을 나타내는 네임 스페이스로 한정되어야한다 constants::mass_earth.
whn

12

당신의 생각의 기차와 일치 할 수있는 또 다른 대안은 네임 스페이스 (또는 중첩 된 네임 스페이스)를 사용하여 상수를 올바르게 그룹화하는 것입니다. 예를 들면 다음과 같습니다.

namespace constants {
   namespace earth {
      constexpr double G = 6.67408e-11;
      constexpr double Mass_Earth = 5.972e24;
      constexpr double GM = G*Mass_Earth;
   }// constant properties about Earth

   namespace fluid {
      constexpr double density = 0.999; // g/cm^3
      constexpr double dyn_viscosity = 1.6735; //mPa * s
   }// constants about fluid at 2C

   // ... 

} // end namespace for constants

위의 기술을 사용하면 참조 상수를 원하는 파일과 네임 스페이스로 지역화하여 전역 변수보다 더 제어 할 수 있으며 유사한 이점을 얻을 수 있습니다. 상수를 사용하면 다음과 같이 간단합니다.

constexpr double G_times_2 = 2.0*constants::earth::G;

중첩 된 네임 스페이스의 긴 체인을 싫어하는 경우 네임 스페이스 별칭을 사용하여 필요할 때 항상 단축 할 수 있습니다.

namespace const_earth = constants::earth;
constexpr double G_times_2 = 2.0*const_earth::G;

2
이것은 OpenFOAM 이 따르는 접근법 입니다. OpenFOAM 소스 코드 의 임의의 예를 참조하십시오 . OpenFOAM은 유체 역학에 널리 사용되는 유한 체적 방법을 구현하는 C ++ 코드 라이브러리입니다.
Dohn Joe

1

내가하는 한 가지 방법은 싱글 톤을 사용하는 것입니다.

프로그램을 시작할 때 싱글 톤을 시작하고 상수 데이터 (아마도 실행할 속성 파일에서)로 채 웁니다. 값이 필요한 모든 클래스에서 이것을 얻고 그냥 사용하십시오.


경고 : 때때로 멀티 스레드 코드에서 단일 톤 액세스를 직렬화했습니다. 따라서 프로파일 링 단계의 일부로이를 확인할 수 있습니다.
Richard

나는 확실히 그것들을 싱글 톤에 넣지 않을 것입니다 ... 실제로 그 상수는 다른 도메인에서 모델을 적용 할 때 미래에 변할 것입니다. 싱글 톤을 사용하면 다른 매개 변수로 테스트하기가 매우 어렵습니다.
André

그것들은 모두 상수입니다. 여기에는 싱글 톤이 필요하지 않습니다. 정적 접근 자 클래스가 여기에 더 좋습니다. 구성 파일에서 값을 가져 오는 정적 클래스가 더 좋습니다 (최종 사용자가 실수가 있거나 더 정밀한 것을 원하면 새로운 빌드를하지 않고도 구성 파일을 조정할 수 있습니다).
스쿠버 스티브

싱글턴은 거의 좋은 생각이 아닙니다. 의존성 주입은 훨씬 깨끗하고 유연한 솔루션입니다. 그러나 상수 만 사용하면 헤더의 상수를 어딘가에 일정하게 유지해야합니다.
mascoj 2019
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.