2016-11-18 17 views
6

İki farklı kitaplık kullanan bir C++ projesi üzerinde çalışıyorum: günlüğe kaydetme için spdlog ve nesneleri baytlara (ağ üzerinden göndermek için) serileştirmek için mutils-serialization. Her iki kitaplık da ad alanlarını düzgün kullanır, ancak her ikisini de aynı anda kullanan bir program yazmayı denediğimde, derleyicim (g ++ 6.2) bana bir işlev şablonunu spdlog kitaplığından başlatmaya çalıştığını gösteren anlamsız hatalar verir. mutils kitaplığından bir işlev şablonunun tanımını kullanarak.Başka bir kitaplıktan şablona eşleştirilen bir kitaplıktan işlev

İşte benim basit bir test programı:

#include <spdlog/spdlog.h> 
#include <spdlog/fmt/ostr.h> 
#include "TestSerializableObject.h" 

int main(int argc, char** argv) { 
    auto global_logger = spdlog::rotating_logger_mt("global_logger", "log", 1024 * 1024 * 500, 3); 
    global_logger->set_pattern("[%H:%M:%S.%e] [%l] %v"); 
    global_logger->set_level(spdlog::level::trace); 

    std::shared_ptr<spdlog::logger> logger(spdlog::get("global_logger")); 

    auto message = std::make_shared<messaging::TestSerializableObject>(
     1, 2, "A message!"); 

    logger->trace("Received a message: {}", *message); 
} 

TestSerializableObjectmutils::ByteRepresentable (seri sağlayan ve mutils-serileştirme kütüphanede çeker arabirimini) uygulayan bir basit sınıftır ve gerekli bir operator<< (sağlar spdlog giriş yapabilmek için). Gerekirse kodu yazabilirim. Ben g++ -std=c++14 -I"./src" -I"./libraries" -I"./libraries/mutils/" -L"./libraries/" -O0 -g3 -Wall "src/LibraryCollisionTest.cpp" ile bu derleme, bu uzun, çirkin hatası alıyorum

(merak etmeyin, bunu ayrıştırmak yardımcı olacağız):

In file included from ./libraries/mutils/mutils.hpp:3:0, 
       from ./libraries/mutils-serialization/SerializationSupport.hpp:2, 
       from src/TestSerializableObject.h:10, 
       from src/LibraryCollisionTest.cpp:10: 
./libraries/mutils/args-finder.hpp: In instantiation of ‘struct mutils::function_traits<messaging::TestSerializableObject>’: 
./libraries/mutils/args-finder.hpp:75:41: required from ‘auto mutils::convert(F) [with F = messaging::TestSerializableObject; ignore = void]’ 
./libraries/spdlog/fmt/bundled/format.h:1276:46: required from ‘struct fmt::internal::ConvertToInt<messaging::TestSerializableObject>’ 
./libraries/spdlog/fmt/bundled/format.h:1485:5: required by substitution of ‘template<class T> fmt::internal::MakeValue<Formatter>::MakeValue(const T&, typename fmt::internal::EnableIf<fmt::internal::Not<fmt::internal::ConvertToInt<T>::value>::value, int>::type) [with T = messaging::TestSerializableObject]’ 
./libraries/spdlog/fmt/bundled/format.h:2465:12: required from ‘static fmt::internal::Value fmt::internal::ArgArray<N, true>::make(const T&) [with Formatter = fmt::BasicFormatter<char>; T = messaging::TestSerializableObject; unsigned int N = 1u]’ 
./libraries/spdlog/fmt/bundled/format.h:2898:5: required from ‘void fmt::BasicWriter<Char>::write(fmt::BasicCStringRef<CharType>, const Args& ...) [with Args = {messaging::TestSerializableObject}; Char = char]’ 
./libraries/spdlog/details/logger_impl.h:69:9: required from ‘void spdlog::logger::log(spdlog::level::level_enum, const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’ 
./libraries/spdlog/details/logger_impl.h:127:5: required from ‘void spdlog::logger::trace(const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’ 
src/LibraryCollisionTest.cpp:21:53: required from here 
./libraries/mutils/args-finder.hpp:12:37: error: ‘operator()’ is not a member of ‘messaging::TestSerializableObject’ 
    : public function_traits<decltype(&T::operator())> 
            ^~ 
./libraries/mutils/args-finder.hpp: In instantiation of ‘auto mutils::convert(F) [with F = messaging::TestSerializableObject; ignore = void]’: 
./libraries/spdlog/fmt/bundled/format.h:1276:46: required from ‘struct fmt::internal::ConvertToInt<messaging::TestSerializableObject>’ 
./libraries/spdlog/fmt/bundled/format.h:1485:5: required by substitution of ‘template<class T> fmt::internal::MakeValue<Formatter>::MakeValue(const T&, typename fmt::internal::EnableIf<fmt::internal::Not<fmt::internal::ConvertToInt<T>::value>::value, int>::type) [with T = messaging::TestSerializableObject]’ 
./libraries/spdlog/fmt/bundled/format.h:2465:12: required from ‘static fmt::internal::Value fmt::internal::ArgArray<N, true>::make(const T&) [with Formatter = fmt::BasicFormatter<char>; T = messaging::TestSerializableObject; unsigned int N = 1u]’ 
./libraries/spdlog/fmt/bundled/format.h:2898:5: required from ‘void fmt::BasicWriter<Char>::write(fmt::BasicCStringRef<CharType>, const Args& ...) [with Args = {messaging::TestSerializableObject}; Char = char]’ 
./libraries/spdlog/details/logger_impl.h:69:9: required from ‘void spdlog::logger::log(spdlog::level::level_enum, const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’ 
./libraries/spdlog/details/logger_impl.h:127:5: required from ‘void spdlog::logger::trace(const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’ 
src/LibraryCollisionTest.cpp:21:53: required from here 
./libraries/mutils/args-finder.hpp:75:41: error: ‘as_function’ is not a member of ‘mutils::function_traits<messaging::TestSerializableObject>’ 
    return function_traits<F>::as_function(f); 
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~ 
In file included from ./libraries/spdlog/fmt/fmt.h:21:0, 
       from ./libraries/spdlog/common.h:41, 
       from ./libraries/spdlog/spdlog.h:12, 
       from src/LibraryCollisionTest.cpp:8: 
./libraries/spdlog/fmt/bundled/format.h: In instantiation of ‘struct fmt::internal::ConvertToInt<messaging::TestSerializableObject>’: 
./libraries/spdlog/fmt/bundled/format.h:1485:5: required by substitution of ‘template<class T> fmt::internal::MakeValue<Formatter>::MakeValue(const T&, typename fmt::internal::EnableIf<fmt::internal::Not<fmt::internal::ConvertToInt<T>::value>::value, int>::type) [with T = messaging::TestSerializableObject]’ 
./libraries/spdlog/fmt/bundled/format.h:2465:12: required from ‘static fmt::internal::Value fmt::internal::ArgArray<N, true>::make(const T&) [with Formatter = fmt::BasicFormatter<char>; T = messaging::TestSerializableObject; unsigned int N = 1u]’ 
./libraries/spdlog/fmt/bundled/format.h:2898:5: required from ‘void fmt::BasicWriter<Char>::write(fmt::BasicCStringRef<CharType>, const Args& ...) [with Args = {messaging::TestSerializableObject}; Char = char]’ 
./libraries/spdlog/details/logger_impl.h:69:9: required from ‘void spdlog::logger::log(spdlog::level::level_enum, const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’ 
./libraries/spdlog/details/logger_impl.h:127:5: required from ‘void spdlog::logger::trace(const char*, const Args& ...) [with Args = {messaging::TestSerializableObject}]’ 
src/LibraryCollisionTest.cpp:21:53: required from here 
./libraries/spdlog/fmt/bundled/format.h:1276:38: warning: invalid application of ‘sizeof’ to a void type [-Wpointer-arith] 
    enum { enable_conversion = sizeof(convert(get<T>())) == sizeof(Yes) }; 

anahtar hat burada:

./libraries/mutils/args-finder.hpp: In instantiation of ‘auto mutils::convert(F) 
[with F = messaging::TestSerializableObject; ignore = void]’: 
./libraries/spdlog/fmt/bundled/format.h:1276:46: required from ‘struct 
fmt::internal::ConvertToInt<messaging::TestSerializableObject>’ 
./libraries/spdlog/fmt/bundled/format.h:1485:5: required by substitution of 
‘template<class T> fmt::internal::MakeValue<Formatter>::MakeValue(const 
T&, typename fmt::internal::EnableIf<fmt::internal::Not< 
fmt::internal::ConvertToInt<T>::value>::value, int>::type) [with T = 
messaging::TestSerializableObject]’ 

Her nasılsa, g ++ spdlog kitaplığı içindeki templated bir işlevi, fmt::internal ad alanında, mutemet kitaplığındaki bir işlev şablonuna, mutils ad alanı içinde, spdlog kitaplığının ne yapmak istediği açıkça belli olmayan bir şekilde genişletmekten atladı! Yeterince emin yukarıda

template<typename T> 
struct ConvertToInt 
{ 
    enum { enable_conversion = sizeof(convert(get<T>())) == sizeof(Yes) }; 
    enum { value = ConvertToIntImpl2<T, enable_conversion>::value }; 
}; 

Birkaç satır, fonksiyon "convert" dir: Ben format.h hattı 1276 bakarsak, bu şablon yapı içinde "convert" işlevini çağıran biri

template <typename T> 
T &get(); 

Yes &convert(fmt::ULongLong); 
No &convert(...); 

Tüm bunlar fmt::internal ad alanı içinde yer almaktadır ve IDE, 1276 numaralı satırın "dönüştürülmesi" işlevinin tanımını istiyorsanız, 1248 numaralı satırdaki "dönüştür" işlevine atlamam gerektiğini kabul eder. Bu nedenle, g ++ bunu dikkate almaz tanımı ve bunun yerine, doğru ad alanında bile olmayan mutils::convert() tanımını kullanmayı deneyin.

Ayrıca clang bu programı derleme başarısız ve aynı hata yapar, bu yüzden g ++ bir hata olduğunu düşünmüyorum.

+2

Spdlog'da bir düzeltme yapıldı (https://github.com/gabime/spdlog/commit/d6b34d7b5c62a0000d96939ad946b85a2274f2bb) – GabiMe

+0

Teşekkürler @GabiMe! Yeni sürümü kontrol ettim ve sorunumu çözdüm. – Edward

cevap

9

Bu, spdlog dosyasında bir hatadır.

sorun bu SSS özetle açıklanmıştır:
What is “Argument-Dependent Lookup” (aka ADL, or “Koenig Lookup”)?

messaging::TestSerializableObject Çünkü devralır bir türünden bir TestSerializableObject ile ad fmt::internal içinden niteliksiz denir convert ad mutils, içinde, hem fmt::internal::convertvemutils::convert aşırı yük setinde kabul edilir. Variadic fonksiyonlar her zaman aşırı yüklenme çözünürlüğü sırasında son sıraya girer, bu yüzden bu argümandaki F şablon argümanı, eskiden ...'dan daha iyi eşleşir ve mutils::convert seçilir.

Bu, hiçbir şekilde, aynı ad alanında veya aynı ad alanında convert isimli tekil işlevli bir işlev veya işlev şablonuna sahip herhangi bir türde kodunuza veya – kümesine özel değildir.

düzeltmeconvert çağrıyı hak ve ben her zaman için tüm çağrıları eleme alışkanlık haline

enum { enable_conversion = sizeof(convert(get<T>())) == sizeof(Yes) }; 

kendi kodunda

enum { enable_conversion = sizeof(internal::convert(get<T>())) == sizeof(Yes) }; 

ila fmt::internal::ConvertToInt<T>::enable_conversion tanımını değiştirmektir, aynı ad alanı içindeki koddan bile internal/ detail ad boşluğunda, işlevleri daha az ADL kullanımı açıkça amaçlanmıştır. (N.b. çağrıları, sadece kalifiye nitelikli olmak zorunda değildir.) Bu dersi, Boost'un C++ 11'in ortaya çıkması gibi zor bir yolla uğraştığını izlemekten öğrendim. : -]

+2

Veya yardımcıları statik üye işlevleri olarak özellik sınıfına taşıyın. Adın bir sınıf üyesine dönüşmesi durumunda ADL yok. Biri, muhtemelen çok ince olmasına rağmen, 'dönüştürmeyi' parantezleyebilir. –

+0

@ T.C. : Doğru, parantezleme olasılığından bahsetmeyi düşündüm, ama bu, C++ geliştiricilerinin% 90'ının bilmediği şeylerden biri. Gerçekten çok ince. – ildjarn

+0

Ayrı kitaplıklardan gelenler arasında aşağıdaki gibi bir çarpışma olduğunda son çare olarak: Bazen kendi cpp dosyalarınızın her birinde iki kitaplıktan birini kullanmak için basit bir çözümdür. –

İlgili konular