2010-07-20 20 views
10

मैंने सी ++ में एक वास्तविक मस्तिष्क स्कोचर पर मारा है, यह पहले कभी मेरे साथ नहीं हुआ है।सी ++ टेम्पलेट फ़ंक्शन गलत डिफ़ॉल्ट मान

समस्या का सारांश यह है कि मेरे (टेम्पलेट) फ़ंक्शन के आविष्कार पर तर्कों को परिभाषित करने के लिए मैंने उनके मानों को स्कैम्बल किया है। यह केवल तब होता है जब मैं फ़ंक्शन को डिफ़ॉल्ट के साथ कॉल करता हूं।

template <typename T> 
vector2<T> transform(vector2<T> const &vec, matrix4<T> const &m, T z = T(0), T w = T(1)); 

यह बाद में, एक ही शीर्षक में, इस तरह परिभाषित किया गया है:

मेरे टेम्पलेट समारोह इस तरह घोषित किया जाता है

template <typename T> 
inline vector2<T> transform(vector2<T> const &vec, matrix4<T> const &m, T z, T w) 
{ 
vector4<T> res = m * vector4<T>(vec.x, vec.y, z, w); 
return vector2<T>(res.x, res.y); 
} 
अब

जब मैं के साथ चूक (transform(vector2<double>(0, 1), view_transform)) मैं इस फोन मुझे उम्मीदों को प्राप्त न करें। वीसी ++ एस डीबगर के साथ में कदम उठाने में मुझे z और w "मजेदार" मान (जो मेरे अनुभव में है कि कुछ ठीक से शुरू नहीं किया गया है) देखें।

उदाहरण अजीब मूल्यों होगा: 0.0078125000000000000 और 2.104431116947e-317 # डेन

अब मैं, पर सी ++ पूछे जाने वाले प्रश्न लाइट उत्तर ढूंढना यह googling की कोशिश की है; शूबर्ट के साथ खुद को शांत करने की भी कोशिश की, लेकिन मैं इसके जीवन के लिए इसे समझ नहीं सकता। मुझे लगता है कि यह वास्तव में सरल है और मुझे संदेह है कि यह काम पर किसी प्रकार का टेम्पलेट टॉमफूलरी है।

क्या मेरे द्वारा अपेक्षित डिफ़ॉल्ट मूल्यों को प्राप्त करने और इच्छित करने का कोई तरीका है, और यह मेरे साथ ऐसा क्यों करता है?

संपादित करें 1:

अगर मैं परिवर्तन कॉल तो यह तैरता बजाय का उपयोग करता है (transform(vector2<float>(0, 1), view_transform)) समस्या दूर चला जाता है। ऐसा प्रतीत होता है कि यह तब होता है जब T = double

संपादित करें 2:

यह केवल होता है अगर मैं double और float के लिए दो विशेषज्ञताओं की है। यदि मैं एक स्थान पर एक फ्लोट विशेषज्ञता का उपयोग करता हूं तो डबल विशेषज्ञता अजीब डिफ़ॉल्ट मान प्राप्त करती है। यदि मैं उन सभी स्थानों को बदलता हूं जिन्हें फ़ंक्शन कहा जाता है, तो यह "दूर चला जाता है" समस्याओं को दोगुना उपयोग करता है। मुझे अभी भी समझ में नहीं आ रहा है कि क्यों, ऐसा लगता है कि यह z और w सेट करते समय दोषपूर्ण ऑफ़सेट या कुछ का उपयोग कर रहा है।

संपादित करें 3: सी ++ क्रिप्ट से

किस्से:

#include <sgt/matrix4.hpp> 

int main(int argc, char *argv[]) 
{ 
    sgt::matrix4<double> m0(
     2, 0, 0, 1, 
     0, 2, 0, 1, 
     0, 0, 1, 0, 
     0, 0, 0, 1); 

    m0 *= m0; 

    sgt::vector2<double> blah0 = sgt::transform(sgt::vector2<double>(1, 0), m0); 

    sgt::matrix4<float> m1(
     2, 0, 0, 1, 
     0, 2, 0, 1, 
     0, 0, 1, 0, 
     0, 0, 0, 1); 

    m1 *= m1; 

    sgt::vector2<float> blah1 = sgt::transform(sgt::vector2<float>(1, 0), m1); 

    printf("%f", blah0.x); 
    printf("%f", blah1.x); 
} 

matrix4.hpp में:

// ... 

template <typename T> 
vector2<T> transform(vector2<T> const &vec, matrix4<T> const &m, T z = T(0), T w = T(1)); 

template <typename T> 
inline vector2<T> transform(vector2<T> const &vec, matrix4<T> const &m, T z, T w) 
{ 
    vector4<T> res = m * vector4<T>(vec.x, vec.y, z, w); 
    return vector2<T>(res.x, res.y); 
} 

// ... 

अगर मैं चलने वाले, डबल विशेषज्ञता है यह डिफ़ॉल्ट है तर्क सही हैं, लेकिन फ्लोट संस्करण को शून्य (0.000000) के रूप में डिफ़ॉल्ट तर्क दोनों मिलते हैं, हालांकि यह अभी भीनहीं है 210 और w = 1

संपादित 4:

एक Connect issue बनाया।

+0

मुझे इसके साथ कुछ भी गलत नहीं दिखाई दे रहा है ... क्या आप इसे एक अलग कंपाइलर के तहत आजमा सकते हैं? –

+1

आप किस कंपाइलर का उपयोग कर रहे हैं और आप किस प्लेटफॉर्म पर हैं? – Alerty

+1

आह क्षमा करें, उस जानकारी को भूल गए, माइक्रोसॉफ्ट वीसी ++ 10 (16.00.30319.01)। @j_random_hacker: हम्म, ठीक है, मैं मिनजीडब्ल्यू डाउनलोड कर सकता हूं और कोशिश कर सकता हूं। – Skurmedel

उत्तर

5

निम्नलिखित देव स्टूडियो में मेरे लिए विफल रहता है:

#include "stdafx.h" 
#include <vector> 
#include <iostream> 

template <typename T> 
std::vector<std::vector<T> > transform(std::vector<std::vector<T> > const &vec, 
             std::vector<std::vector<std::vector<std::vector<T> > > > const &m, 
             T z = T(0), T w = T(1)); 


template <typename T> 
std::vector<std::vector<T> > transform(std::vector<std::vector<T> > const &vec, 
             std::vector<std::vector<std::vector<std::vector<T> > > > const &m, 
             T z, T w) 
{ 
    std::cout << "Z" << z << "\n"; 
    std::cout << "W" << w << "\n"; 

    return vec; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::vector<std::vector<int> > xi; 
    std::vector<std::vector<std::vector<std::vector<int> > > > mi; 
    transform(xi,mi); 

    std::vector<std::vector<float> > xf; 
    std::vector<std::vector<std::vector<std::vector<float> > > > mf; 
    transform(xf,mf); 

    std::vector<std::vector<double> > xd; 
    std::vector<std::vector<std::vector<std::vector<double> > > > md; 
    transform(xd,md); 
} 

आउटपुट:

Z0 
W1 
Z0 
W1.4013e-045 
Z2.122e-314 
W3.60689e-305 

तो मैं यह अपेक्षा के अनुरूप काम नहीं करता है लगता है !!!

यदि आप पूर्व-घोषणा हटाते हैं और टेम्पलेट फ़ंक्शन में डिफ़ॉल्ट तर्क डालते हैं तो यह अपेक्षित कार्य करता है।

#include "stdafx.h" 
#include <vector> 
#include <iostream> 

template <typename T> 
std::vector<std::vector<T> > transform(std::vector<std::vector<T> > const &vec, 
             std::vector<std::vector<std::vector<std::vector<T> > > > const &m 
             T z = T(0), T w = T(1)) 
{ 
    std::cout << "Z" << z << "\n"; 
    std::cout << "W" << w << "\n"; 

    return vec; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::vector<std::vector<int> > xi; 
    std::vector<std::vector<std::vector<std::vector<int> > > > mi; 
    transform(xi,mi); 

    std::vector<std::vector<float> > xf; 
    std::vector<std::vector<std::vector<std::vector<float> > > > mf; 
    transform(xf,mf); 

    std::vector<std::vector<double> > xd; 
    std::vector<std::vector<std::vector<std::vector<double> > > > md; 
    transform(xd,md); 
} 

यह अपेक्षा के अनुसार काम करता है।
इस टेम्पलेट प्री-घोषणा के साथ कुछ करने के लिए वास्तव में एक फ़ंक्शन प्री-घोषणा नहीं है और इस प्रकार इसमें वास्तव में डिफ़ॉल्ट पैरामीटर नहीं हैं और इस तरह आपको पैरामीटर सूची में यादृच्छिक मान मिल रहे हैं।

ठीक है।

का उपयोग n2521
धारा 14.7.1 अंतर्निहित इन्स्टेन्शियशन
अनुच्छेद 9

कार्यान्वयन परोक्ष एक समारोह टेम्पलेट का दृष्टांत नहीं करेगा, एक सदस्य टेम्पलेट: नहीं मानक के मेरे पढ़ने से इस अपेक्षा के अनुरूप काम करना चाहिए , एक गैर-आभासी सदस्य funcion, एक सदस्य वर्ग या एक वर्ग टेम्पलेट का एक स्थिर डेटा सदस्य जिसके लिए तत्काल आवश्यकता नहीं है। वर्चुअल सदस्य फ़ंक्शन अन्यथा तत्काल नहीं होने पर यह कार्यान्वित किया गया है कि कोई कार्यान्वयन एक क्लास टेम्पलेट के आभासी सदस्य फ़ंक्शन को तत्काल लागू नहीं करता है या नहीं। डिफ़ॉल्ट तर्क में टेम्पलेट विशेषज्ञता का उपयोग टेम्पलेट को तत्काल तत्काल नहीं ठहराया जाएगा, सिवाय इसके कि एक वर्ग टेम्पलेट को तत्काल किया जा सकता है जहां डिफ़ॉल्ट तर्क की शुद्धता निर्धारित करने के लिए इसका पूर्ण प्रकार आवश्यक है। फ़ंक्शन कॉल में डिफ़ॉल्ट तर्क का उपयोग डिफ़ॉल्ट तर्क में विशेषज्ञता को तत्काल तत्काल करने का कारण बनता है।

अनुच्छेद के बोल्ड हिस्सा (मेरे लिए) लगता है संकेत मिलता है कि क्योंकि डिफ़ॉल्ट तर्कों के बनाए गए प्रत्येक विशेषज्ञता परोक्ष जब इस्तेमाल किया अनुवाद इकाई में instantiated कर दिया जाएगा।

अनुच्छेद 11:

एक समारोह टेम्पलेट च एक तरीका है कि एक डिफ़ॉल्ट तर्क अभिव्यक्ति की आवश्यकता है में कहा जाता है, तो प्रयोग की जाने वाली निर्भर नाम ऊपर देखा जाता है, अर्थ विज्ञान की कमी जाँच कर रहे हैं, और के इन्स्टेन्शियशन डिफ़ॉल्ट तर्क अभिव्यक्ति में उपयोग किए गए किसी भी टेम्पलेट को ऐसा किया जाता है जैसे डिफ़ॉल्ट तर्क अभिव्यक्ति एक स्वाद के साथ एक फ़ंक्शन टेम्पलेट विशेषज्ञता में उपयोग की जाने वाली अभिव्यक्ति थी, उसी टेम्पलेट पैरामीटर और उसी बिंदु पर फ़ंक्शन टेम्पलेट f के समान उपयोग । इस विश्लेषण को डिफ़ॉल्ट तर्क तत्काल कहा जाता है। तत्काल डिफ़ॉल्ट तर्क तब एफ के तर्क के रूप में प्रयोग किया जाता है।

इंगित करता है कि डिफ़ॉल्ट तर्क टेम्पलेट पैरामीटर हैं, भले ही वे सही ढंग से तत्काल हो जाएंगे।

अच्छी तरह से मुझे आशा है कि मैंने इसे सही तरीके से व्याख्या की है। :-)

+0

क्या आप दो अलग-अलग विशेषज्ञताओं (मेरे नवीनतम संपादन को देखें) के साथ कॉल करने का प्रयास कर सकते हैं, जैसे डबल और फ्लोट दोनों का उपयोग करना? यह वीसी ++ की तरह गंध शुरू हो रहा है यहाँ कुछ मजेदार कर रहा है। – Skurmedel

+0

हाहा ओह प्रिय, कभी नहीं पता था कि डिफ़ॉल्ट मूल्य यह बुरा हो सकता है। – Skurmedel

+0

क्या किसी ने इसे g ++/MinGW पर आजमाया है?यदि यह अवैध सी ++ है तो निश्चित रूप से सी ++ मानक एक कंपाइलर त्रुटि संदेश को जरूरी करेगा ...? –

1

मुझे नहीं पता कि यह काम करेगा या नहीं, लेकिन अपने डिफ़ॉल्ट मानों के लिए सी स्टाइल कास्ट के बजाय static_cast का उपयोग करने का प्रयास करें।

* संपादित करें: जाहिर है, समस्या संकलक है।

+0

दुखद परिणाम एक ही परिणाम देता है। – Skurmedel

+3

तकनीकी रूप से वह सी-स्टाइल कास्ट नहीं था लेकिन एक पैरामीटरयुक्त कन्स्ट्रक्टर कॉल था। –

+0

@ ड्रू हॉल: यह एक कन्स्ट्रक्टर कॉल नहीं है। – Alerty

2

क्या कोड अनुकूलित किया गया है? शायद यही कारण है कि डीबगर आपको गलत मान दिखा रहा है।

मैंने इस सरल कोड (जी ++ 4.3.3 में) की कोशिश की और यह अपेक्षा के अनुसार काम करता है।

template <typename T> 
T increment(T a, T b = T(1)) 
{ 
    return a + b; 
} 

int main() 
{ 
    double a = 5.0; 
    std::cout << increment(a) << ", "; 
    std::cout << increment(a, 3.0) << "\n"; 
} 
+0

यह रिलीज और डीबग (ऑप्टिमाइज़ेशन ऑफ) दोनों में एक ही व्यवहार दिखाता है, लेकिन यह जांच कर रहा है कि क्या इससे कोई फर्क पड़ता है, मैंने एक अजीब चीज़ खोज ली। यह केवल तभी होता है जब टी डबल हो, न कि यह तैरता है ?! – Skurmedel

संबंधित मुद्दे